2017-04-22 105 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,無論哪一個是EOF時,是否打印輸出? – 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; 
} 

編譯&在Cygwin的測試在Windows 10 (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. 我在解析器的lex源碼以及line規則中引入了EOL標記。

  3. 在測試過程中,我發現第二個輸入每次都在語法錯誤中結束。我需要一段時間,直到我意識到語法現在實際上僅限於接受一行。因此,我在解析器源中插入了遞歸input規則。