2017-05-18 10 views
0

이 Bison 프로그램에 문제가 있습니다. 재사용이 효과가없는 이유를 모르겠습니다. 음수로 작업하려면 첫 번째 숫자를 얻고 더 많은 연산을 수행하기 위해 같은 줄을 사용하면됩니다. 방금 첫 번째 숫자를 음수로 변경했습니다.비손과 플렉스로 계산이 작동하지 않습니다. 부정확합니다.

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에서 Bison의 훌륭한 설명서를 간단히 들었을 수 있습니다. 그러나 누가 설명서를 읽었습니까? – deamentiaemundi

+0

uhmmm 잘 시도해 보겠습니다. 나는이 환경에서 새로운 것입니다. 그런데 어떻게 작동하는지 정말 잘 모릅니다. 하지만 고마워, 최선을 다하겠습니다. –

+0

단항 마이너스가 올바른 연관성이 있어야합니다. – user3344003

답변

2

으로 내 의견에, 문제는 "단항 마이너스"라고하고는 정상 감산 a - b 구별의 문제를 설명했다 부정 처리 작업 0 - a에서 축약 된 경우 -a. 일반적인 해결책은 위치에 따라 두 개의 다른 연산자로 마이너스 기호를 사용하는 코드를 추가하는 것입니다. Bison에서는 존재하지 않는 심볼 (여기 NEG)에 우선 순위를 구현하고 그 우선 순위를 케이스 -a에 바인딩합니다.

T_FLOAT에 대해 한 번, T_INT에 대해 두 번 코드에서 두 번 수행해야합니다. 적어도 나에게는 의미가없는 한 줄을 삭제했다.

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

구현하려는 언어에 따라 나머지 연산자에 우선 순위 및 연관성을 추가 할 수도 있습니다. (또는 당신은 문법을 배제 할 수 있지만, Bison이 당신을 위해 연산자 우선 순위를 취할 것이기 때문에, 왜 귀찮게합니까? :-)) – torek

+0

고마워요.하지만 그것을 적용하는 법을 이해하지 못했습니다. 나는 그것을 내 방식대로하고 작동합니다. http://prntscr.com/f9nvlh –

+0

@torek의 목표에 따르면 : 하나의 질문, 하나의 대답. 나는 여기에서 자신을 제한하는 법을 배웠다. 그렇지 않으면이 대답은 SO의 길이 제한을 초과했을 것이다. – deamentiaemundi