2013-11-22 77 views
0

這是我的野牛代碼:Bison分析器計算器

%} 

%union { 
int int_val; 
} 


%left '+' '-' 
%nonassoc '(' ')' 

%token INTEGER PRINT 
%type <int_val> expr_int INTEGER 

%% 
program: command '\n' { return 0; } 
     ; 
command: print_expr 
     ; 
print_expr: PRINT expr_int   { cout<<$2<<endl; } 
expr_int: expr_int '+' expr_int  { $$ = $1 + $3; } 
     | expr_int '-' expr_int  { $$ = $1 - $3; } 
     | '(' expr_int ')'     { $$ = $2; } 
     | INTEGER 
     ; 

,這是Flex代碼:

%} 

INTEGER  [1-9][0-9]*|0 
BINARY  [-+] 
WS    [ \t]+ 
BRACKET  [\(\)] 

%% 
print{WS}    { return PRINT; } 
{INTEGER}    { yylval.int_val=atoi(yytext); return INTEGER; } 
{BINARY}|\n  { return *yytext; } 
{BRACKET}    { return *yytext; } 
{WS}     {} 
.      { return *yytext; } 

%% 

////////////////////////////////////////////////// 
int yywrap(void) { return 1; } // Callback at end of file 

該計劃無效的輸入是:

print 5 

輸出:

5 

輸入:

print (1+1) 

輸出:

2 

但由於某些原因,有以下輸入我沒有得到立即的錯誤:

print (1+1)) 

輸出:

2 
some error 

輸入:

print 5! 

輸出:

5 
some error 

我想錯誤立即被打印,而不commiting打印命令,然後發出一個錯誤。

我應該如何改變程序,所以它不會打印errornous投入?

+0

編譯器懲罰你調用括號「括號」。 –

回答

0

爲您的語言創建行尾標記(例如;),並在遇到此行尾標記時準確確定所有行語句。

+0

我真的不明白該怎麼辦..你能複製並糾正我的鱈魚嗎? – Jjang

0

那是因爲你在解析它的時候正在執行代碼。好的老野牛計算器是爲了教你如何編寫一個語法,而不是實現一個完整的編譯器/解釋器。

建立編譯器/解釋器的正常方式如下:

lexer -> parser -> semantic analyser -> code generator -> interpreter 

授予構建一個完全成熟的編譯器,你的情況可能是矯枉過正。你需要的是將結果存儲在某個地方,並且僅在yyparse已經返回而沒有錯誤之後才輸出。

1

下載的「彎曲&野牛」一書由約翰·萊文或GNU的「野牛」手冊。兩者都包含一個你可以參考的中綴計算器。 。

你寫 「 '(' expr_int ')'」 語法降低之前在語法上不正確 ')' 以expr_int「(1 + 1))」檢測到的解析器的作用:

(1 + 1)) => (expr_int)) => expr_int) 

,然後看到錯誤。爲了捕捉你必須改變解析器看到錯誤減少錯誤之前,你必須這樣做對於要處理的所有錯誤。因此,你會寫(在這種情況下):

expr_int「(」 expr_int「)」「)」 {這是一個錯誤信息}

簡短的回答,長的回答後,就在於它是不切實際生成一個包含所有可能錯誤實例的解析器。你所擁有的對你正在做的事情很好。您應該探索的是如何(正常)從錯誤中恢復,而不是放棄解析。

你的「節目」和「命令」非終端可以組合爲:

program: print-expr '\n' { return 0; } 

在一個單獨的說明,你的正則表達式可以改寫良好效果:

%% 
INTEGER  [0-9]+ 
WS   [ \t]+ 

%% 
print/{WS}    { return PRINT; } 
{INTEGER}    { yylval.int_val=atoi(yytext); return INTEGER; } 
'('      { return '(';  } 
')'      { return ')';  } 
'+'      { return '+';  } 
'-'      { return '-';  } 
{WS}*     {} 
\n      { return '\n'; } 
.      { return *yytext; } // do you really want to do this? 

%% 
0

在YACC /野牛,具有語義動作相關的代碼,只要有問題的規則,減少執行,可能已被轉移,尋找任何以下上下文之前,看看是否有錯令牌的規則後立即發生或者不是(所謂的「默認」減少,用於使分析表更小)。

如果你想避免打印一個答案,直到整個行被讀取(和認可),您需要包括在具有打印消息的操作規則中的換行符。你的情況,你可以從program規則移動換行到print_expr規則:

program: command { return 0; } ; 
print_expr: PRINT expr_int '\n' { cout<<$2<<endl; } 

當然,這仍然會給你一個錯誤,如果你給它輸入的多行(打印輸出後)。

+0

真的不推薦'return 0'部分。在這種情況下,它是無用的,否則,應該使用'YYABORT'。 – akim