5

2 + 2=4および2.2+2=4.2を実行するプログラムを作成することになっています。

すべてを浮動小数点として扱うようにすでに実行しましたが、それは「間違っています」。私はそれらを区別する必要があります。これが私がこれまでに持っているものです:

%{
#include <stdio.h>
#include <ctype.h>
%}

%token <dval> FLOAT
%token <ival> INTEGER

%union
{
   float dval;
   int ival;
}

%type <dval> command exp term factor

%%

command : exp           {printf("%f\n",$1);}
    ;

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

term    : term '*' factor   {$$ = $1 * $3;}
    | factor        {$$ = $1;}
    ;

factor : '(' exp ')'        {$$ = $2;}
    | FLOAT         {$$ = $1;}
    | INTEGER       {$$ = $1;}
    ;

%% 

int main()
{ 
  return yyparse();
}

int yylex()
{
   int c;
   while( (c=getchar()) == ' ');
   if( isdigit(c) )
   {
      ungetc(c, stdin);
      float f1;
      scanf("%f", &f1);
      int i1 = (int) f1;
      if(f1 == 0)
      {
         yylval.ival = 0;
     return INTEGER;
      }
      else if( (((float) i1) / f1 ) == 1)
      {
     yylval.ival = i1;
         return INTEGER;
      }
      else
      {
     yylval.dval = f1;
     return FLOAT;
      }
      //scanf("%f",&yylval.dval);
      //return(NUMBER);
   }
   if(c == '\n') return 0;
   return c;
}

int yyerror(char *s)
{
   fprintf(stderr,"%s\n",s);
   return 0;
}

私が抱えている問題は、各式が持つことができるタイプは1つだけであるということです。現在、すべてが基本的にフロートであるため、操作は正しいものの、これは適切なソリューションではありません。

基本的にfactor_intとfactor_floatを使用して、より多くの式を定義し、その中のすべてを置き換えることを考えましたが、それは本当に間違っているようです。しかし、これをどのように行うかはわかりません。また、私が見たチュートリアルは実際には役に立ちませんでした。

4

3 に答える 3

2

基本的に、次のようなことができます。

%{
#include <stdio.h>
#include <ctype.h>

struct number
{
  union
  {
    int ival;
    float fval;
  }
  char type;
}

char INT_TYPE = 1;
char FLOAT_TYPE = 2;

%}

%union
{
   struct number value;
}

%token <value> FLOAT INTEGER command exp term factor

int yylex()
{
   ...
   if(f1 == 0)
   {
     yylval.value.type = INT_TYPE;
     yylval.value.ival = 0
   }
   ...
}

等々..

このようにして、ルールを削減するときにオペランドをチェックして、新しい正しいタイプを確実に生成できます。次に例を示します。

exp : exp '+' term {
   if ($1.type == INT_TYPE && $3.type == INT_TYPE)
   {
      $$.type = INT_TYPE;
      $$.ival = $1.ival + $3.ival;
   }
   else if ($1.type == INT_TYPE && $3.type == FLOAT_TYPE)
   {
      // this is a sort of implicit conversion to float
      $$.type = FLOAT_TYPE; 
      $$.fval = $1.ival + $3.fval;
   }
   // and so on

}

PS。Flex + Bisonでも同様のことをしましたが、Lex + Yaccと同様にすべてがサポートされているかどうかはわかりませんが、そう思います。

于 2010-03-02T21:34:39.467 に答える
0

yylval struct/union内でデータ型をエンコードします。

+演算子などの可能なすべての組み合わせを記述する代わりに、yaccで+演算子のルールを1つだけ定義し、実行時にデータ型(yylvalに格納されている)の有効性を確認します。

コンテナまたは配列を使用してすべての有効な組み合わせを格納し、このコンテナを使用して実行時に有効性を確認します。有効な組み合わせが見つからない場合は、「申し訳ありませんが、日付とフロートを追加することはできません」のように、少なくとも適切な実行時エラーを出すことができます。構文エラーの代わりに(yaccで個別のルールを定義すると発生します)。

ケーキの最後のアイシングとして、「自動変換」ロジックを追加します。有効な組み合わせが見つからない場合は、オペランドの1つを別のタイプに変換してみてください。そのような典型的なハードコードされた変換の1つは、「intからfloat」です。たとえば、コンテナで2つの整数または2つの浮動小数点数の追加のみが許可されており、ユーザーが1 + 3.14(整数+浮動小数点数)を入力した場合、コンテナ内に有効な組み合わせは見つかりません。intをfloatに変換し、コンテナーをもう一度確認します。コンバージョン数がそれほど多くない場合は、十分に高速である必要があります。

于 2010-03-02T20:59:09.293 に答える
0

@Jackの答えはうまくいくと思いますが、すべてのルールをfloatの計算に基づいて作成し、一番上のルール(最後に評価されるルール)に基づいて結果が整数かどうかを確認する方が簡潔かもしれません。またはフロートを使用して、適切な結果を出力します。

主な方法は次のようになります。

main(){
 return yyparse();
}

int yylex(void){
 int c;
   while((c = getchar()) == ' ');
   if (isdigit(c)){
     ungetc(c, stdin);
     scanf("%lf", &yylval);
     return NUMBER;
   }
   if ( c == '\n'){
  return 0;
 }
   return c;
}

int yyerror(char * s){
 fprintf(stderr, "%s\n", s);
   return 0;
}

そして、最上位のルールを次のように変更する必要があります。

/*This is where we distinguish between float and integer*/
    command  : exp{
        if((((int)$1) / $1) ==  1){
         printf("%d\n", (int)$1);
        }
        else{
         printf("%lf\n", $1);
        }
       }
      ;

%typeこのアプローチを使用すると、必要なトークンは1つだけで(FLOATとINTEGERの代わりにNUMBER)、演算子を説明するためにソースコードにもう1つのステートメントを追加する必要があります。%unionその場合、ステートメントにはとが含まれdouble val;ますchar op;

于 2010-11-21T01:15:57.753 に答える