逆ポーランドプログラムについての解説をお願いします

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
大工

逆ポーランドプログラムについての解説をお願いします

#1

投稿記事 by 大工 » 18年前

またまた逆ポーランドについての質問です。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "stack.h"//自作ヘッダーファイル.

#define STACK_SIZE 100
#define NUM        256
#define DONE       257

static int token(int *val);
static void error_recover(stack_t *stack, char *msg);

int main ( void ){
	stack_t *stack;
	int tok;
	int val, x, y;

	//スタックを作成する.

	if( (stack = create_stack(STACK_SIZE)) == NULL ){
		fprintf(stderr, "failed to create stack.\n");
		exit(EXIT_FAILURE);
	}
	printf("> ");
	for(;;){
		if((tok = token(&val)) == DONE){
			break;
		}
		switch(tok){
			case NUM:
				push(stack, val);
				break;
			case '+':
				y = pop(stack); x = pop(stack);
				push(stack, x + y);
				break;
			case '-':
				y = pop(stack); x = pop(stack);
				push(stack, x - y);
				break;
			case '*':
				y = pop(stack); x = pop(stack);
				push(stack, x * y);
				break;
			case '/':
				y = pop(stack); x = pop(stack);
				if(y == 0){
					error_recover(stack, "divide by zero");
					continue;
				}
				push(stack, x / y);
				break;
			case '\n':
				if(sp_read(stack) == 1){
					printf("%d\n", pop(stack));
					printf("> ");
					break;
				}
				ungetc(tok, stdin);//ここです。
			default: //不正なトークンを検出.
				error_recover(stack, "invalid input");
				printf("> ");
				break;
		}
	}

	free(stack);

	return EXIT_SUCCESS;
}

stack_t *create_stack(unsigned int sz){
	stack_t *new_stack;
	//スタックデータの確保.
	new_stack = (stack_t*)malloc( sizeof(stack_t) + sizeof(int)*(sz - 1) );
	if(new_stack == NULL){
		return NULL;
	}
	new_stack->top = 0;
	new_stack->size = sz;

	return new_stack;
}
/*
  push:
	引数で指定したスタックstackに値numをプッシュする.
*/
void push(stack_t *stack, int num){
//スタックが満杯の場合はメッセージを出力して終了する.
	if(is_full(stack)){
		fprintf(stderr, "stack overflow.\nss");
		exit(EXIT_FAILURE);
	}
	stack->data[stack->top++] = num;
}
/*
  pop:
	引数で指定したスタックstackから値をポップする.
*/
int pop(stack_t *stack){
	//スタックが空の場合はメッセージを出力して終了する.
	if(is_empty(stack)){
		fprintf(stderr, "stack underflow.\n");
		exit(EXIT_FAILURE);
	}
	return stack->data[--stack->top];
}
//token: トークンを取得する.
static int token(int *val){

	int ch;

	while ((ch = getchar()) != EOF){
		if(ch == ' ' || ch == '\t'){
			continue;
		}
		else if(isdigit(ch)){
			ungetc(ch, stdin);
			scanf(" %d", val);
			return NUM;
		}
		else{
			return ch;
		}
	}
	return DONE;
}
//error_recover: エラーからの回復処理.
static void error_recover(stack_t *stack, char *msg){

	int ch;

	fprintf(stderr, "ERROR: %s.\n", msg);
	init_stack(stack);//init_stack(st) ((st)->top = 0)
	while((ch = getchar()) != EOF){
		if(ch == '\n') return;
	}
	exit(EXIT_FAILURE);
}
typedef struct stack{
	int top;       //スタックトップの位置.
	int size;      //データ部の大きさ.
	int data[1];   //データ部.
} stack_t;

//スタックの状態を判定するマクロ.
#define is_empty(st)   ((st)->top == 0)
#define is_full(st)    ((st)->top == (st)->size)
#define sp_read(st)    ((st)->top)
#define init_stack(st) ((st)->top = 0)

//スタック操作関数のプロトタイプ宣言.
extern stack_t *create_stack(unsigned int sz);
extern void push(stack_t *st, int num);
extern int pop(stack_t *st);
のようなプログラムがあったとしてungetc(tok, stdin); はどのような機能をもっているんですか??(このプログラム上で)
あと、getcharは今まで使ったことがあるのですが今回の様な使い方を見たことがないのでなぜこのプログラムでは文字を入力することができているのかを教えて下さい><;;;(scanfのように)

管理人

Re:逆ポーランドプログラムについての解説をお願いします

#2

投稿記事 by 管理人 » 18年前

>getcharは今まで使ったことがあるのですが今回の様な使い方を見たことがない

そうですか?このような書き方は
while((ch = getchar()) != EOF){
	if(ch == '\n') return;
}
最も一般的なように思います。処理の順番はOKでしょうか。
getcharで取って来たデータをchに格納し、それがエンドオブファイルじゃなければループを行う。
取って来たデータが改行だったらリターン。

という意味です。つまりエンターが押されたら終了するわけですね。

もう一つgetchar関数が書いてありますが、上記の要領でながれを確認してください。

ungetc関数は私も見たこと無かったんですが、検索すれば沢山説明が出てきました。
例えばこの辺が参考になりそうです。
http://www.nurs.or.jp/~sug/soft/super/ungetch.htm

これは検索をかけてトップに出てきました。
使い方のわからない関数があればたいていそれをgoogleなどで検索すれば、沢山説明が出てきます。

大工

Re:逆ポーランドプログラムについての解説をお願いします

#3

投稿記事 by 大工 » 18年前

あ、分かりました!!! &val は単なる引数だったんですね!!てっきりscanf(" %d", &val) って意味かと思いました!!ww


とりあえずungetc は一度読み込んだ文字をバッファに戻して読み込まなかったことと言うわけなんですね!
case '\n':
				if(sp_read(stack) == 1){
					printf("%d\n", pop(stack));
					printf("> ");
					break;
				}
				ungetc(tok, stdin);//ここです。
だと、sp_read(stack) == 1 ではないときに改行コードを読み込まなかったことにしているということでしょうか??

管理人

Re:逆ポーランドプログラムについての解説をお願いします

#4

投稿記事 by 管理人 » 18年前

>だと、sp_read(stack) == 1 ではないときに・・・

いえ、if文の外にあり、elseでもないところに書いてあるので
1の時でも処理が行われているでしょう。

閉鎖

“C言語何でも質問掲示板” へ戻る