2017-04-22 19 views
0

私はコンパイラとプログラミング言語の作り方を理解しようとしています。そして、そうするために、私は単なる加算と減算を行う単純な電卓を作成することを考えました。以下は、LexおよびYaccのファイルです。単純な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にはbisonマニュアルの例があります。 – 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; 
} 

コンパイル&は、Windows 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. テスト中に、2番目の入力が構文エラーで毎回終了したことがわかりました。文法が実際には1行を正確に受け入れることが実際に制限されていることを認識するまで、私はしばらく時間が必要でした。したがって、再帰的なinputルールをパーサーソースに挿入しました。

関連する問題