2017-02-12 14 views
1

私は、コンパイラと、.txtファイルから複数行の方程式(各行に1つの方程式)を入力することを学ぶことに慣れています。そして私はセグメンテーションフォールトの問題に直面しています。算術yaccプログラムの入力ファイルを複数行読み込むには?

YACCコード:

%{ 
#include <stdio.h> 
#include <string.h> 
#define YYSTYPE int /* the attribute type for Yacc's stack */ 
extern int yylval;  /* defined by lex, holds attrib of cur token */ 
extern char yytext[]; /* defined by lex and holds most recent token */ 
extern FILE * yyin; /* defined by lex; lex reads from this file */ 
%} 

%token NUM 

%% 

Begin : Line   
    | Begin Line  
    ; 
Line : Calc     {printf("%s",$$); } 
    ; 
Calc : Expr     {printf("Result = %d\n",$1);} 
Expr : Fact '+' Expr  { $$ = $1 + $3; } 
    | Fact '-' Expr  { $$ = $1 - $3; } 
    | Fact '*' Expr  { $$ = $1 * $3; } 
    | Fact '/' Expr  { $$ = $1/$3; } 
    | Fact     { $$ = $1;   } 
    | '-' Expr    { $$ = -$2;  } 
    ; 
Fact : '(' Expr ')'   { $$ = $2;   } 
    | Id     { $$ = $1;   } 
    ; 
Id : NUM     { $$ = yylval;  } 
    ; 

%% 

void yyerror(char *mesg); /* this one is required by YACC */ 

main(int argc, char* *argv){ 
char ch; 
if(argc != 2) {printf("useage: calc filename \n"); exit(1);} 
if(!(yyin = fopen(argv[1],"r"))){ 
     printf("cannot open file\n");exit(1); 
} 
yyparse(); 
} 

void yyerror(char *mesg){ 
    printf("Bad Expression : %s\n", mesg); 
    exit(1); /* stop after the first error */ 
} 

LEXコード:

%{ 
#include <stdio.h> 
#include "y.tab.h" 
int yylval; /*declared extern by yacc code. used to pass info to yacc*/ 
%} 

letter [A-Za-z] 
digit [0-9] 
num  ({digit})* 
op  "+"|"*"|"("|")"|"/"|"-" 
ws  [ \t\n] 
other . 

%% 

{ws} { /* note, no return */ } 
{num} { yylval = atoi(yytext); return NUM;} 
{op} { return yytext[0];} 
{other} { printf("bad%cbad%d\n",*yytext,*yytext); return '?'; } 

%% 
/* c functions called in the matching section could go here */ 

私は結果と一緒に式を印刷しようとしています。 ありがとうございました。あなたのパーサで

答えて

1

、あなたが持っている:今

Line : Calc     {printf("%s",$$); } 

$$は、ルールが計算されたセマンティック値であり、そしてあなたはそれには何も割り当てられていません。したがって、それが未定義であると仮定することは不合理ではないでしょう。これは悪いですが、実際にはデフォルト規則$$ = $1;のために値があります。すべて同じで、書くのがはるかに読みやすくなります

printf("%s", $1); 

しかし、それは間違いですね。結局のところ、あなたは持っている

#define YYSTYPE int 

ですので、すべての意味型は整数です。しかしprintfには$1が文字列(%s)であると伝えています。 printfはあなたを信じているので、intはあたかもそれがchar*であるかのように逆参照しようとしますが、予測可能な結果(つまり、segfault)があります。

int%s形式コードで印刷しようとしていることに気付くほど巧妙なコンパイラを使用している可能性があります。しかし、コンパイラに助けを求めることも、アドバイスを無視していることもありません。

常に警告を有効にしてコンパイルします。 gccまたはclangを使用している場合は、-Wallをコマンドラインに入力することを意味します。 (他のコンパイラを使用している場合は、警告の生成方法を調べてください。)また、プログラムを実行する前に警告を読み、修正してください。


コードには他にもいくつかのエラーや疑わしい習慣があります。あなたの文法は間違っています(なぜ、すべての演算子の左オペランドとしてfactを使用しますか?)あなたの言い回しにもかかわらず、字句スキャナは改行文字を無視するので、パーサーが式が1行に1つであるか、 1行に2つ、または複数行にまたがって表示されます。コマンドラインツールとして電卓を使用するのが難しくなります。

レックスマクロdigitを定義する必要はありません。 (f)lexは、Posix文字クラス[[:digit:]](およびその他、documented here)を自動的に認識します。また、マクロnumを定義することは特に有用ではありません。lexマクロを過度に使用すると、プログラムの読み込みが困難になります。それだけの場所にパターンを書き込むために、通常は優れている:あなたのためにとあなたのコードを読む人のために、両方の仕事がより読みやすく、より少ないだろう

[[:digit:]]+  { yylval = atoi(yytext); return NUM; } 

。 (あなたの教授や教師が同意しない場合は、直接問題を話し合うことができます。)

+0

rici私はそれをyaccコードをコンパイルすると成功するが、20のシフト/メッセージ。私は出力を得ることができますが、式は.txtではありません。例:2 + 3 *( - 7)は.txtですが、ファイルリーダーコードを書くと、yyerrorメッセージがスローされます。 –

+0

@nikul:回答した後で質問を変更しないでください。 SOは質問と回答のリポジトリであることを意図しています。質問を変更すると回答が無効になり、その情報は他の人に価値がありません。答えがあなたに役立つなら、あなたはそれに投票したり、それを受け入れることができます。あなたがそれをダウンボートしたり、無視したりすることはできますが、どちらの場合でも別の質問がある場合は、別の質問としてそれを聞いてください。 – rici

+0

すみません、私はこのサイトを初めて知りませんでした。 –

関連する問題