C言語アルゴリズム-計算式 |
3.3 変数の処理
入力された計算式を評価するevale.cに変数が使用できる処理を追加する。
計算式には、数値以外に変数が使用できる。変数名は先頭の1文字だけで区別するので、使用できる変数は26個だけである。また、変数は0で初期化されるものとする。
変数に値を格納するために代入文が使用可能である。
OK : a=11+20*30 OK : ?a 611.000000 OK : x=1.23 OK : y=4.56 OK : z=x*10+y*10 OK : ?x;y,z 1.230000 4.560000 57.900000 OK : ?1.2-3.4+1.2 -1.000000 OK : ! |
<変数>=<値>また、<値>を表示するために ? 命令を追加してある。使用方法は、BASICのPRINT命令と同じである。
<値>:数値、変数、計算式
? 12, a; 1+2
プログラムを終了するための ! 命令(BASICのEND命令と同じ)を追加する。
ただし、これまでのように計算式だけでは実行できない。
[evalv.c] | |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: |
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <setjmp.h> #include "gettoken.h" /* gettoken.c */ double expression(void); /* 式 */ double term(void); /* 項 */ double factor(void); /* 因子 */ double number(void); /* 数値データ */ void errorx(char *, char *); /* エラー処理 */ void assign(void); /* 代入文 */ void exec_print(void); /* ? 命令 */ jmp_buf env; /* setjmp 用 */ double val[26]; /* 変数用 A - Z */ void main(void) { while(1){ printf("OK : "); gets(gt_line); get_token(); if(*token == '\0') /* 空入力 */ break; if(setjmp(env) == 0){ /* longjmp()の戻り位置 */ if(*token == '?') /* 表示 */ exec_print(); else if(*token == '!') /* 終了 */ break; else if(isalpha(*token)) /* 代入文 */ assign(); else errorx("このような命令はない", token); } } } void assign(void) { int index; index = toupper(*token) - 'A'; /* 格納場所である配列の添え字を計算 */ get_token(); if(*token != '=') errorx("代入文の文法がおかしい", token); get_token(); /* 評価結果を変数領域に格納 */ val[index] = expression(); } void exec_print(void) { while(1){ get_token(); if(*token == '\0') break; else printf("% f", expression()); /* 継続処理 */ if(*token == ',') printf("\t"); else if(*token == ';') printf(" "); else if(*token == '\0') break; else errorx("?命令に誤りがある", token); } printf("\n"); } double expression(void) { double ans; ans = term(); while(1){ if(*token == '+'){ get_token(); ans = ans + term(); }else if(*token == '-'){ get_token(); ans = ans - term(); }else break; } return(ans); } double term(void) { double ans, x; ans = factor(); while(1){ if(*token == '*'){ get_token(); ans = ans * factor(); }else if(*token == '/'){ get_token(); x = factor(); if(x == 0) errorx("0では割れない", "0"); ans = ans / x; }else break; } return(ans); } double factor(void) { double ans; if(*token == '('){ get_token(); ans = expression(); if(*token != ')'){ printf(")がない\n"); exit(1); } get_token(); return(ans); }else return(number()); } double number(void) { double ans; char sign; if(*token == '+' || *token == '-'){ /* 符号判定 */ sign = *token; get_token(); } if(isalpha(*token)) /* 先頭英字 */ ans = val[toupper(*token) - 'A']; /* 変数の内容取得 */ else if(isdigit(*token)) /* 先頭数字 */ ans = atof(token); /* 数字を実数値に変換 */ else errorx("数字または変数名でなければならない", token); get_token(); if(strchr("+-*/),;", *token) == NULL) errorx("演算子でなければならない", token); if(sign == '-') return(-ans); return(ans); } void errorx(char *s1, char *s2) { printf("%s <%s>\n", s1, s2); do{ get_token(); /* 行の終わりまで読み飛ばす */ }while(*token != '\0'); longjmp(env, 1); } |
16行目は、変数のデータを格納するための配列をグローバルで宣言している。変数Aの値は配列val[0]に、変数Zの値は配列val[25]に格納される。これは、A〜Zの文字コード(0x41〜0x5a)が連続しているので、各文字コードから0x41(A)を減じれば配列の添え字が得られる。
27〜34行で、入力データが表示命令(?)、終了命令(!)か代入文かを判定している。
代入文を処理する関数assignでは、
42行目で、右辺の変数値の格納場所である配列の添え字を計算している。変数は英小文字でも使えるように関数toupperで大文字に変換してから計算している。
43行目で、次のトークンを取り出す。代入文であるから=のはずである。
44行目で、=かどうか判定し、=でなければ45行目でエラー処理関数errorxを呼び出している。
48行目で、計算式処理の関数expressionを呼び出し、その結果を配列valに格納している。
表示命令(?)を処理する関数exec_printでは、
57行目で、<値>の表示をしている。 <値>:数値、変数、計算式
59〜62行目で、続きの<値>があるかどうかを判定している。
値を取り出す関数numberでは、値の種類として変数が出てくる。
132行目で、変数かどうか判定し、変数であれば133行目でその値を取り出している。
134行目で、数字かどうか判定し、数字であれば135行目で数値に変換している。
139行目の、関数strchrは第1引数の文字列の中に第2引数の文字があるかどうかを調べる関数である。無ければNULLを返す。
Copyright © 2001 Hiroshi Masuda |