2017-02-12 80 views
1

我是編譯器新手,學習如何使用計算器從.txt文件輸入多行方程(每行一個方程)。而我正面臨着分段錯誤的問題。如何爲算術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*一樣,並帶有可預測的結果(即段錯誤)。

您可能正在使用一種編譯器,該編譯器足夠聰明,可以注意到您正嘗試使用%s格式的代碼打印int。但是要麼你沒有要求編譯器幫助你,要麼你忽略了它的建議。

總是在啓用警告的情況下編譯。如果您使用的是gcc或clang,那意味着在命令行中輸入-Wall。 (如果您正在使用其他編譯器,請了解如何生成警告,並將其記錄下來。)然後在嘗試運行該程序之前閱讀警告並修復它們。


你的代碼還有其他一些錯誤和/或可疑的做法。你的語法不準確(你爲什麼使用fact作爲每個操作符的左邊操作數?),儘管你的註釋中,你的詞法掃描器忽略了換行符,所以解析器無法知道表達式是否每行一個,每行兩個,或分佈在多行;這將使得很難將計算器用作命令行工具。

沒有必要定義lex宏digit; (f)lex自動識別Posix字符類[[:digit:]](和其他人,documented here)。定義宏num也不是特別有用。過度使用lex宏使得程序難以閱讀;它通常是最好只寫模式出來到位:

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

這將是更具可讀性和較少的工作都爲你和任何人閱讀你的代碼。 (如果你的教授或導師不同意,我很樂意直接與他們討論這個問題。)

+0

rici我用Expr更新了Fact事物,現在當我編譯它時,yacc代碼成功了,但是提供了20次轉換/減少衝突信息。我能夠得到輸出但不是.txt中的表達式例如:2 + 3 *( - 7)是在.txt中,但是當我編寫文件讀取器代碼時,它會拋出yyerror消息。 –

+0

@nikul:在回答問題後請不要更改您的問題。 SO旨在成爲問題和答案的存儲庫;當你改變你的問題時,你使答案無效,然後這些信息對其他人沒有任何價值。如果答案對您有幫助,您可以爲其投票和/或接受;如果沒有,你可以降低或忽略它,但無論是哪種情況,如果你還有其他問題,請將它作爲另一個問題。 – rici

+0

很抱歉,我是這個網站的新手,我不知道。 –