
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
No.3
- 回答日時:
トークンは数字、演算子などの一塊の意味のある文字列とでも
考えてください。
(ファイルだけではなく)文字列中に収められた式などを扱う場合、コンピュータではそのままでは
扱えないので、一旦意味の解釈をしやすい単位(トークン単位)に変換します。
この後で、トークン同士の関係を見ながら、式の意味を解析して
計算していきます。
トークンに解析する際は、文字列からトークンを切り出すので、
解析対象の文字列から1文字ずつ読み込んで判断する必要があります。
1文字ずつなので、これはfgetcで取り込んでも良いですし、
fgetsで1行分取り込んで、読み込みバッファから1文字ずつ読み込む
(char* buff[i])でもいいです。
結局、ファイルに書かれている内容は、単純にcharの配列としてしか
見てくれないので、文字列のデータを意味のあるデータに変換し、
計算を行わせる必要があります。この処理は、コンピュータで自動的に
やってくれないので、全て手動で行う必要があります。
(fscanfなどでは扱えないということになります)
解析処理自体は、kotonさんが対応させたい式の要素(=トークン)に
分解できれば良いので、汎用でなければ、ある程度コンパクトに出来ると思います。
後は、試行錯誤していくしかないと思います(^^;
#こういう、構文解析などは学校の課題でやった記憶はありますが・・・
No.2
- 回答日時:
以前、整数の数式を処理するのに、作ったCのプログラムです。
ちゃんとした、数式の解析をやっていないので、そういう点ではあんまり参考にならないかもしれませんが、参考までに
剰余計算(%)は未実装ですが、割り算とほぼ同じ考えでいけると思います。
()が最優先で、*/が同列で、+-が同列左優先で計算しています。
参考URLは、OKWebでアップするのに、JAVAで書いたバージョンです。やっていることは、ほぼ同じです。(有理数演算になっています)
C++の場合、java版からの方が簡単に変更できるかもしれません。
-------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXLEN 80
#define STACKSIZE 3
int calc(char *str){
/* (3+5)*7-2 のような文字列を計算する */
char cstack[STACKSIZE]; /* 演算子スタック */
int vstack[STACKSIZE]; /* 値スタック */
int vsp,csp;
int level;
int sign=0;
int wk=0;
char buff[MAXLEN];
char *p,*pwk,cwk;
/* trim */
for(pwk=p=str;*p;p++)
if(*p=='\t' || *p==' ')
continue;
else
*pwk++=*p;
*pwk=*p;
vsp=csp=STACKSIZE;
cstack[--csp]='@';/* empty mark */
p=str;
while(*p){
if(isdigit(*p)){
if(sign==0)sign=1;
wk=wk*10+ *p++ - '0';
} else { /* 数字以外の文字が現れた時は、数が決定する */
if(sign!=0)vstack[--vsp]=sign*wk; /* 数をスタックに積む */
wk=0; /* wkを次の数の読み取りのために初期化する */
sign=0;
switch(*p){
case '*':
case '/':
cwk=cstack[csp];
if(cwk=='@' || cwk=='+' || cwk=='-')
cstack[--csp]=*p;
else{
if(cwk=='*')
vstack[vsp+1]*=vstack[vsp];
else if(cwk=='/')
vstack[vsp+1]/=vstack[vsp];
vsp++;
cstack[csp]=*p;
}
p++;
break;
case '-':
if(str==p){
sign=-1;
p++;
break;
} else if(NULL!=strchr("*/+-",*(p-1))){
sign=-1;
p++;
break;
}
case '+':
cwk=cstack[csp];
if(cwk=='@')
cstack[--csp]=*p;
else {
switch(cwk){
case '+':
vstack[vsp+1]+=vstack[vsp];break;
case '-':
vstack[vsp+1]-=vstack[vsp];break;
case '*':
vstack[vsp+1]*=vstack[vsp];break;
case '/':
vstack[vsp+1]/=vstack[vsp];break;
}
vsp++;
cstack[csp]=*p;
}
p++;
break;
case '(': /* カッコ中身でcalcを呼び出す */
p++;
level=1;
sign=1;
for(pwk=buff;*p;p++){
if(*p==')'){
if(--level==0){
*pwk='\0';
wk=calc(buff);
break;
}
} else if(*p=='('){
level++;
}
*pwk++=*p;
}
if(level){/* カッコの数が合っていない時 */
*pwk='\0';
wk=calc(buff);
} else
p++;
break;
case ')':/* ありえないはず */
p++;
fprintf(stderr,"閉じカッコが多すぎる\n");
break;
default:
fprintf(stderr, "使用できない文字[%c]がある\n",*p++);
}
}
}
vstack[--vsp]=sign*wk;
while('@'!=(cwk=cstack[csp++])){
switch(cwk){
case '+':
vstack[vsp+1]+=vstack[vsp];break;
case '-':
vstack[vsp+1]-=vstack[vsp];break;
case '*':
vstack[vsp+1]*=vstack[vsp];break;
case '/':
vstack[vsp+1]/=vstack[vsp];break;
}
vsp++;
}
return (vstack[vsp]);
}
void main(void){
char buff[MAXLEN];
gets(buff);
printf("=%d\n", calc(buff));
exit(EXIT_SUCCESS);
}
参考URL:http://okweb.jp/kotaeru.php3?q=1384055
No.1
- 回答日時:
数式の書き方のバリエーションがあり過ぎるので、fscanf では困難かと思います。
数式を読み込んで処理するという場合セオリー通りやるとしたら、
---
(1) fgets で行ごと読み込んで、
(2) トークン単位に分解しつつ、
(3) 優先順位を考慮して値を計算する
---
という事になります。トークン単位の分解というのは、上記の例では「8」「%」「(」「1」「+」「3」「)」という具合に、数値や演算子単位に切り出す事です。
優先順位の考慮は、「%」より「(」「)」の方を優先して計算しなければならないという事で、スタックを使って優先度の低い計算を一時棚上げしておいて優先度の高い方の計算が終わったら、続きを計算するといった処理が必要です。
この辺りの処理は、説明し出すと本が書けてしまう程長くなるので、詳しくはコンパイラの教科書的な本を読むと良いと思います。
学生の時にコンパイラの授業でこういった理論を学んで目からウロコだった記憶があります。読んでおいて損はありません!今でもものすごく参考になっています。
この回答への補足
なるほどfgetsですか。ありがとうございます。
トークン単位というのはfgets(buff,255,fp)と
buffに読み込んで処理するのですか?
%cで一文字ずつ読み込んで数か否かを判別すると
言うのを思いついたのですが、どうやるのか分からないので悩んでいます。
教科書にはトークン単位は載っていませんでした。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) エクセルでSUMIFS関数で条件範囲の部分が#valueになる。 4 2023/04/28 12:42
- C言語・C++・C# C# で、あるフォルダー内にあるすべてのテキストファイルを別のフォルダーにコピーする。 4 2022/11/21 13:23
- その他(プログラミング・Web制作) pythonでクラスで複数のメソッドを利用する方法 2 2022/04/15 04:17
- Excel(エクセル) エクセルのVBAについて とあるサイトのコードを参考に、CSVの文字化けを直すVBAを作成しているの 7 2022/11/04 14:15
- その他(プログラミング・Web制作) Pythonで、データファイルと列名ファイルを1つのファイルにしたいです。 1 2023/07/27 20:29
- C言語・C++・C# C言語の質問です。バイナリ形式で保存されたWindows Bitmap形式の画像ファイルを読み込み、 3 2023/07/19 14:58
- その他(プログラミング・Web制作) 【python】Excelファイルを読み込む際の日付の表示形式を任意にする 2 2022/11/24 14:21
- C言語・C++・C# pythonで外部のファイルを読み込む際のエラー 2 2022/04/12 19:22
- Visual Basic(VBA) 【VBA】写真の縦横比を変えずに貼り付ける 5 2023/06/13 11:42
- その他(動画サービス) YMM4 で MOV ファイルが読み込まれているがプレビューされない 2 2022/07/25 18:36
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
65536は2の何乗なのでしょうか?
-
太陽の位置計算のプログラムを...
-
matlabで計算終了
-
EXCELなどで「返す」という表現
-
逆行列求めたい
-
数値計算の高速化 (cos, sin, exp)
-
VBAの再計算が反映されない件に...
-
VBAで関数をつくる
-
MATLABの積分について
-
連立方程式を解くプログラムを...
-
[急募]Pythonについてです。
-
C言語 Σをつかったプログラム
-
WEBページ上で計算をさせるには...
-
smartyで計算を行う方法
-
変化させるセルが変化しない
-
パソコン
-
matlab計算での進捗状況を知りたい
-
引き放し法による除算アルゴリ...
-
Date型の範囲を超える数値について
-
スパイダソリティアの問題
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
65536は2の何乗なのでしょうか?
-
VBAの再計算が反映されない件に...
-
排他的論理和 BCC(水平パリテ...
-
EXCELなどで「返す」という表現
-
変化させるセルが変化しない
-
エクセルで特定のセルのみを任...
-
CとFORTRANの計算速度はどちら...
-
モジュロ
-
バッチファイルでウインドウを...
-
Visual C++でdebugとreleaseで...
-
y=(x^2 +3x+1)^4を微分の定義を...
-
入射角反射角
-
スレッド処理からダイアログを...
-
60進数の四則計算
-
Javaと他言語比較について
-
VBAで関数をつくる
-
C言語 Σをつかったプログラム
-
CRC8を教えてください
-
C言語についてです。 再帰を使...
-
C言語について 下の画像は do-w...
おすすめ情報