逆ポーランド記法
1+2*3 は計算の優先順位がはっきりするようにカッコを付けて書くと
(1+(2*3))である。
演算子(四則演算など)をはさむ二つの項に対して演算するこの記法は、中置記法と呼ばれ、私たちが通常記述する記法はこの記法である。
これに対して、前置き記法・後置き記法と呼ばれる記法がある。たとえば、1+2を前置き記法で記述すると、+ 1 2。後置記法で記述すると 1 2 + となる。後置記法は逆ポーランド記法とも呼ばれ、2 項演算子が出現したとき、その直前の 2 項を対象に演算を行うため、カッコがなくても演算の順序はきまる。演算は、演算子がでてくるまではスタックと呼ばれる箱に演算項をいれておき、演算子がでてきたら、スタックから演算項を二つ取り出して、演算を行い、その結果を再びスタックにいれておくことで実現する。
基本仕様
●入力は逆ポーランド記法で行う。
●fgets()で文字列として配列に読み込み、^d の入力でプログラムを終了する。
●数字列(実数を含む)を数値に変換する関数を作成する。
●各項は、空白もしくは演算子によって区切られる。
●スタックは実数型配列を用いて表現する
●四則演算が可能であるとする
●単項演算子は考えなくてよい 例えば -5(マイナス5)など
実行例 (^D で終了する)
1 2 3 * +
計算結果 7.000
1 2 + 3 -
計算結果 0.000
1 2 3 * + 4 5 6 + / +
計算結果 7.364
教科書やインターネットを参考にして自分なりにプログラムを作ったのですがセグメンテーション違反のようです。
本当はfgets()で入力を行わないといけませんし、大域変数も使用してはいけません。
いろんな情報をかき集めてつくったので自分でもよくわからないプログラムになってしまいました。。。
一応プログラムソースを載せておきます。
基本仕様にあったプログラムを教えていただけると幸いです。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define N 100
#define num '0'
void ungetch(int);
//文字列の入力
int getStr(char str[])
{
int i,c;
while((str[0]=c=getch())==' ' || c=='\t');
str[1] = '\0';
if(!isdigit(c) && c != '.'){ //cが数でないならcを返す
return c;
}
i=0;
if(isdigit(c)){ //cが1~9なら取り込む
while (isdigit(str[i++]=c=getch()));
}
if(c=='.'){ //cが小数点なら取り込む
while (isdigit(str[++i]=c=getch()));
str[i]='\0';
}
if (c!=EOF){
ungetch(c);
}
return num;
}
double stack[N];
//fを値スタックにプッシュする
double push(double f,int *sp)
{
if(*sp<N){
stack[(*sp)++]=f;
}else{
printf("error: stack full, can't push %g\n", f);
}
}
//スタックをポップし,一番上の値を返す
double pop(int sp)
{
if(sp>0){
return stack[--sp];
}else{
printf("error: stack empty\n");
return 0.0;
}
}
char buf[N];
int bufp =0;
int getch(void) /* 1文字を取ってくる */
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* 文字を入力に戻す */
{
if (bufp >=N)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
main()
{
int type,sp;
double op2;
char str[N];
while((type = getStr(str)) != EOF) {
switch (type) {
case num:
push(atof(str),&sp);
break;
case '+':
push(pop(sp) + pop(sp),&sp);
break;
case '*':
push(pop(sp) * pop(sp),&sp);
break;
case '-':
op2 = pop(sp);
push(pop(sp) - op2,&sp);
break;
case '/':
op2 = pop(sp);
if (op2 != 0.0){
push(pop(sp) / op2,&sp);
}else{
printf("error: zero divisor\n");
}
break;
case '\n':
printf("%.3f\n", pop(sp));
break;
default:
printf("error: unknown command %s\n", str);
break;
}
}
return 0;
}