2017-05-18 10 views
0

このBisonプログラムに問題があります。再利用がうまくいかない理由はわかりません。負の数での演算については、最初の数値を取得するために同じ行を使用し、より多くの演算で操作します。私はちょうど最初の数を負に変更しました。bisonとflexでCalcが動作しないネガ

calc.y

%{ 

#include <stdio.h> 
#include <stdlib.h> 

extern int yylex(); 
extern int yyparse(); 
extern FILE* yyin; 

void yyerror(const char* s); 
%} 

%union { 
    int ival; 
    float fval; 
} 

%token<ival> T_INT 
%token<fval> T_FLOAT 
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT 
%token T_NEWLINE T_QUIT 
%left T_PLUS T_MINUS 
%left T_MULTIPLY T_DIVIDE 

%type<ival> expression 
%type<fval> mixed_expression 

%start calculation 

%% 

calculation: 
     | calculation line 
; 

line: T_NEWLINE 
    | mixed_expression T_NEWLINE { printf("\tResult: %f\n", $1);} 
    | expression T_NEWLINE { printf("\tResult: %i\n", $1); } 
    | T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); } 
; 

mixed_expression: T_FLOAT      { $$ = $1; } 
     | T_MINUS T_FLOAT { $$ = -$2; }  
     | mixed_expression T_PLUS mixed_expression  { $$ = $1 + $3; } 
     | mixed_expression T_MINUS mixed_expression { $$ = $1 - $3; } 
     | mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; } 
     | mixed_expression T_DIVIDE mixed_expression { $$ = $1/$3; } 
     | T_LEFT mixed_expression T_RIGHT  { $$ = $2; } 
     | T_MINUS mixed_expression T_RIGHT   { $$ = -$2; } 
     | expression T_PLUS mixed_expression  { $$ = $1 + $3; } 
     | expression T_MINUS mixed_expression  { $$ = $1 - $3; } 
     | expression T_MULTIPLY mixed_expression { $$ = $1 * $3; } 
     | expression T_DIVIDE mixed_expression  { $$ = $1/$3; } 
     | mixed_expression T_PLUS expression  { $$ = $1 + $3; } 
     | mixed_expression T_MINUS expression  { $$ = $1 - $3; } 
     | mixed_expression T_MULTIPLY expression { $$ = $1 * $3; } 
     | mixed_expression T_DIVIDE expression  { $$ = $1/$3; } 
     | expression T_DIVIDE expression  { $$ = $1/(float)$3; } 
; 

expression: T_INT    { $$ = $1; } 

     | expression T_PLUS expression { $$ = $1 + $3; } 
     | expression T_MINUS expression { $$ = $1 - $3; } 
     | expression T_MULTIPLY expression { $$ = $1 * $3; } 
     | T_LEFT expression T_RIGHT  { $$ = $2; } 
     | T_MINUS T_INT { $$ = -$2; } 
; 

%% 

int main() { 
    yyin = stdin; 

    do { 
     yyparse(); 
    } while(!feof(yyin)); 

    return 0; 
} 

void yyerror(const char* s) { 
    fprintf(stderr, "Parse error: %s\n", s); 
    exit(1); 
} 

calclex.l

%option noyywrap 

%{ 
#include <stdio.h> 

#define YY_DECL int yylex() 

#include "calc.tab.h" 

%} 

%% 

[ \t] ; // ignore all whitespace 
[0-9]+\.[0-9]+ {yylval.fval = atof(yytext); return T_FLOAT;} 
[0-9]+  {yylval.ival = atoi(yytext); return T_INT;} 
\n  {return T_NEWLINE;} 
"+"  {return T_PLUS;} 
"-"  {return T_MINUS;} 
"*"  {return T_MULTIPLY;} 
"/"  {return T_DIVIDE;} 
"("  {return T_LEFT;} 
")"  {return T_RIGHT;} 
"exit"  {return T_QUIT;} 
"quit"  {return T_QUIT;} 

%% 
+0

この問題の原因を「単項マイナス」といいます。例えば、http://www.gnu.org/software/bison/manual/html_node/Infix-Calc.htmlでバイソンの細かいマニュアルを少し垣間見ることができましたが、マニュアルを読むのは誰ですか、 – deamentiaemundi

+0

uhmmmよく私は試してみる、私はこの環境で新しいですし、私は実際にこれをどのように動作するのかわかりません。しかし、ありがとう私は最高をしようとします –

+0

単項マイナスは、正しい結合である必要があります。 – user3344003

答えて

2

私のコメントで言ったように、問題は "単項マイナス" と呼ばれ、それは通常の減算動作を区別するのトラブルを説明しているa - b否定操作0 - aから省略された場合は-a。一般的な解決策は、マイナス記号を位置に応じて2つの異なる演算子として動作させるためのコードを少し追加することです。 Bisonでは、存在しないシンボル(ここではNEG)の優先順位を実装し、その優先順位をケース-aにバインドすることによって行われます。

T_FLOATの場合は1回、T_INTの場合は2回、コードで2回実行する必要があります。少なくとも私のためには意味をなさない1行も削除しました。

calc.y:(浮動小数点数は、もう少し複雑であるが)

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

extern int yylex(); 
extern int yyparse(); 
extern FILE* yyin; 

void yyerror(const char* s); 
%} 

%union { 
    int ival; 
    float fval; 
} 

%token<ival> T_INT 
%token<fval> T_FLOAT 
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT 
%token T_NEWLINE T_QUIT 
%left T_PLUS T_MINUS 
%left T_MULTIPLY T_DIVIDE 

%precedence NEG /* unary minus */ 

%type<ival> expression 
%type<fval> mixed_expression 

%start calculation 

%% 

calculation: 
     | calculation line 
; 

line: T_NEWLINE 
    | mixed_expression T_NEWLINE { printf("\tResult: %f\n", $1);} 
    | expression T_NEWLINE  { printf("\tResult: %i\n", $1); } 
    | T_QUIT T_NEWLINE   { printf("bye!\n"); exit(0); } 
; 

mixed_expression: T_FLOAT       { $$ = $1; } 
     | T_MINUS mixed_expression %prec NEG   { $$ = -$2; }  
     | mixed_expression T_PLUS mixed_expression  { $$ = $1 + $3; } 
     | mixed_expression T_MINUS mixed_expression { $$ = $1 - $3; } 
     | mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; } 
     | mixed_expression T_DIVIDE mixed_expression { $$ = $1/$3; } 
     | T_LEFT mixed_expression T_RIGHT    { $$ = $2; } 
     /* | T_MINUS mixed_expression T_RIGHT    { $$ = -$2; } */ 
     | expression T_PLUS mixed_expression   { $$ = $1 + $3; } 
     | expression T_MINUS mixed_expression   { $$ = $1 - $3; } 
     | expression T_MULTIPLY mixed_expression  { $$ = $1 * $3; } 
     | expression T_DIVIDE mixed_expression   { $$ = $1/$3; } 
     | mixed_expression T_PLUS expression   { $$ = $1 + $3; } 
     | mixed_expression T_MINUS expression   { $$ = $1 - $3; } 
     | mixed_expression T_MULTIPLY expression  { $$ = $1 * $3; } 
     | mixed_expression T_DIVIDE expression   { $$ = $1/$3; } 
     | expression T_DIVIDE expression    { $$ = $1/(float)$3; } 
; 

expression: T_INT         { $$ = $1; } 
     | expression T_PLUS expression     { $$ = $1 + $3; } 
     | expression T_MINUS expression    { $$ = $1 - $3; } 
     | expression T_MULTIPLY expression    { $$ = $1 * $3; } 
     | T_LEFT expression T_RIGHT     { $$ = $2; } 
     | T_MINUS expression %prec NEG    { $$ = -$2; } 
; 

%% 

int main() { 
    yyin = stdin; 
    do { 
     yyparse(); 
    } while(!feof(yyin)); 
    return 0; 
} 

void yyerror(const char* s) { 
    fprintf(stderr, "Parse error: %s\n", s); 
    exit(1); 
} 

ファイルcalclex.lは不変のままにすることができます。

+0

実装したい言語に応じて、残りの演算子に優先順位と連想を追加することもできます。 (あるいは、文法を除外することもできますが、バイソンはあなたのために演算子の優先順位を決めるので、どうして気になるのですか?:-)) – torek

+0

ありがとうございます。しかし、それを適用する方法を理解できませんでした。 私はそれを自分のやり方で行いました。 http://prntscr.com/f9nvlh –

+0

@torekの目標によると:1つの質問、1つの答え。私はここで自分自身を制限することを学んだ、そうでなければこの答えは大きさでSOの長さの制限を超えていただろう;-) – deamentiaemundi

関連する問題