2017-04-22 10 views
0

저는 컴파일러와 프로그래밍 언어가 어떻게 만들어 졌는지 이해하려고합니다. 그리고 그렇게하기 위해서 나는 덧셈과 뺄셈을하는 간단한 계산기를 만드는 것에 대해 생각했습니다. 아래는 LexYacc 파일입니다.간단한 Lex/Yacc 계산기 출력을 출력하지 않습니다.

calc.yacc 파일 :

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

    extern int yylex(); 
    void yyerror(char *); 
%} 

%union { int number; } 
%start line 
%token <number> NUM 
%type <number> expression 

%% 

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

expression: expression '+' NUM { $$ = $1 + $3; }; 
expression: expression '-' NUM { $$ = $1 - $3; }; 
expression: NUM { $$ = $1; }; 

%% 

void yyerror(char *s) { 
    fprintf(stderr, "%s", s); 
    exit(1); 
} 

int main() { 
    yyparse(); 
    return 0; 
} 

calc.lex 파일 :

%{ 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include "y.tab.h" 
%} 

%% 

[0-9]+ { 
    yylval.number = atoi(yytext); 
    return NUM; 
} 

[-+] { return yytext[0]; } 

[ \t\f\v\n] { ; } 

%% 

int yywrap() { 
    return 1; 
} 

그것은 컴파일 잘하지만 난 그것을 실행 한 다음이 걸리면 2 + 4 뭔가를 입력 할 때와 대답을 인쇄하지 않습니다. 왜 누군가가 설명 할 수 있습니까? 제 추측으로는 문법이 정확하지 않다는 것입니다.

+0

운영 체제의 터미널에서 ctrl/d 또는 ctrl/z 중 하나를 입력하면 출력이 인쇄됩니까? – EJP

+0

'ctrl + d'에 답을 인쇄합니다. 하지만 인쇄가 끝나면 'Ctrl + d'키를 누르 자마자 프로그램에서 빠져 나옵니다. 나는 대답을 인쇄 한 후에 더 많은 인풋을 원한다. 어떻게해야합니까? –

+1

계산기가 개행에 응답하게하려면 개행을 문법에 통합해야합니다. Iirc 거기 들소 설명서의 예입니다. – rici

답변

0

나는 rici처럼 같은 생각에 와서 적절하게 샘플 변경 :

파일 calc.l :

%{ 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include "calc.y.h" 
%} 

%% 

[0-9]+ { 
    yylval.number = atoi(yytext); 
    return NUM; 
} 

[-+] { return yytext[0]; } 

"\n" { return EOL; } 

[ \t\f\v\n] { ; } 

%% 

int yywrap() { 
    return 1; 
} 

파일 calc.y :

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

    extern int yylex(); 
    void yyerror(char *); 
%} 

%union { int number; } 
%start input 
%token EOL 
%token <number> NUM 
%type <number> expression 

%% 

input: line input | line 

line: expression EOL { printf("%d\n", $1); }; 

expression: expression '+' NUM { $$ = $1 + $3; }; 
expression: expression '-' NUM { $$ = $1 - $3; }; 
expression: NUM { $$ = $1; }; 

%% 

void yyerror(char *s) { 
    fprintf(stderr, "%s", s); 
    exit(1); 
} 

int main() { 
    yyparse(); 
    return 0; 
} 

컴파일 & 윈도우 10에 Cygwin에서 테스트 (64 비트) :

,
$ flex -o calc.l.c calc.l 

$ bison -o calc.y.c -d calc.y 

$ gcc -o calc calc.l.c calc.y.c 

$ ./calc 
2 + 4 
6 
2 - 4 
-2 
234 + 432 
666 

주 :

  1. 사소한 문제 : 빌드 명령에 따라, 내가 생성 된 토큰 테이블에 대한 #include을 변경했다. (맛의 문제입니다.)

  2. EOL 토큰은 lex 소스뿐만 아니라 파서의 line 규칙에 도입되었습니다.

  3. 테스트 중에 나는 구문 오류로 인해 두 번째 입력이 매번 종료됨을 확인했습니다. 문법이 실제로 한 줄을 정확히 받아들이도록 실제로 제한되었다는 것을 알게 될 때까지 나는 좀 더 필요했다. 따라서 파서 소스에 재귀적인 input 규칙을 삽입했습니다.