LoginSignup
Gucchi612
@Gucchi612

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

bison,flexによる電卓作成

解決したいこと

大学の講義でコンパイラについて学んでおり,bison,flexを用いて電卓プログラムを作成する演習がありました.現在,一つの式は解析できるようになったのですが,複数式は打ち込めません.講義ではヒントとして,「再帰的な規則を使って,複数の式が計算できるようにすること」とありました.どのようにコードを書けばよいのでしょうか.

発生している問題・エラー

(例)1+2の結果が出力された後,3+5を入力に与えた場合
image.png

該当するソースコード

/* 数式の計算 */

%token NUM                                                               /* トークンの定義 */

%{
        int yylex(void);
        void yyerror(const char *s);
        int printf(const char *format, ...);
        int getchar(void);

        int TAB=0x09;           /* タブ */



%}

%%
line    : expr '\n'                  { printf("%d\n", $1); }
        | line expr '\n'             { printf("%d\n", $1); }
        ;

expr    : expr '+' term         { $$=$1+$3; }
        | expr '-' term         { $$=$1-$3; }
        | term                    
        ;

term    : term '*' factor       { $$=$1*$3; }
        | term '/' factor       { if($3 == 0){     
                                        printf("error:devision by zero\n");
                                 }                       /* (d)0による除算はエラー */
                                  else $$=$1/$3;  }
        | term '%' factor       { if($3 == 0){     
                                        printf("error:devision by zero\n");
                                 }                      /* (d)0による除算はエラー */
                                 else $$=$1%$3;  }      /* (a)剰余演算子%の追加 */
        | factor
        ;

factor  : '(' expr ')'          { $$=$2; }
        | '-' NUM               { $$=-$2; }           /* (c)負の数を使えるように */
        | NUM               
        ;

%%

#include <stdio.h>
#include <ctype.h>
/* getchar()     : 1文字ずつ,文字もしくは数字を変数に代入できる関数 */
/* ungetc(int c, FILE *stream)
                 : 後の操作で読み込めるように,cをunsigned char型にキャストして,
                   streamに返す. */
/* isdight(int c): cが数字の場合真(0以外の値),それ以外の場合偽(0)を返す */


char c_exc[] = { '\n','%','(',')','*','+','-','/' };
int check_exc(const char* array, int size,const int c) {
	for (int i = 0; i < size; ++i) {
		if (c == array[i]) {
			return 1;
		}
	}
	return 0;
}




int yylex()                                                          /* 字句解析関数 */
{
    int c;

    while ((c = getchar()) == ' ' || (c == TAB));                    /* (b)空白,タブを読み飛ばす */
    if (isdigit(c)){                                                 /* 数字の処理 */
        yylval = c - '0';                                            /* 0のASCIIコード:0x30 */
        while (isdigit(c = getchar())){                              /* 数字列をint型の値へ */
                yylval = yylval * 10 + (c-'0');
        }
        ungetc(c, stdin);                                            /* 入力の文字を元に戻す */
        return NUM; 
    }               
    else{
        if(check_exc(c_exc,(sizeof c_exc)/(sizeof c_exc[0]),c)==0) {
		printf("error:exceptional word \"%c\"\n",c);         /* 空白,タブ,改行,数字以外の文字はエラー */ 
		yylex();
        }
        else return c;
    }
                                                                                  
}
0

1Answer

手元に環境が無いので試せませんが、以下の修正でどうでしょうか。

line    : expr '\n'                  { printf("%d\n", $1); }
        | line expr '\n'             { printf("%d\n", $2); }
        ;
0Like

Comments

  1. @Gucchi612

    Questioner
    無事正常に動作しました!ありがとうございます.
    C言語記述部分の,擬似変数がいまいちわかっていないのですが,この場合「$1と$2で別のline(式)を表し,再帰的に定義できている」という解釈でよいのでしょうか.
  2. 上記規則の $1 と $2 が表しているのは、line ではなく expr の値です。
    講義のテキストで $1, $2 の意味が説明されていると思うので、参照してください。
  3. @Gucchi612

    Questioner
    理解できました!ご丁寧にありがとうございました.

Your answer might help someone💌