2014-05-07 209 views
1

我正在嘗試使用yacc和lex編寫一個解析器來計算嵌套循環的數量(while或for)。我開始執行for while while循環。但由於某種原因解析器給了我在大括號結尾處出現錯誤。嵌套while循環的Yacc解析器

這是代碼。

%{ 
#include<stdio.h> 
/*parser for counting while loops*/ 
extern int yyerror(char* error); 
int while_count=0; 
extern int yylex(); 
%} 

%token NUMBER 
%token VAR 
%token WHILE 
%% 

statement_list : statement'\n' 
     | statement_list statement'\n' 
       ; 
statement : 
     while_stmt '\n''{' statement_list '}' 
      | VAR '=' NUMBER ';' 
     ; 
while_stmt : 
     WHILE '('condition')'  {while_count++;} 
     ; 

condition : 
      VAR cond_op VAR 
      ; 

cond_op : '>' 
     | '<' 
     | '=''=' 
      | '!''=' 
      ; 

%% 

int main(void){ 
    yyparse(); 
    printf("while count:%d\n",while_count); 
} 

int yyerror(char *s){ 
    printf("Error:%s\n",s); 
    return 1; 
} 

這段代碼有什麼問題。有沒有辦法在yacc中提到可選參數?像「\ n」之後一樣?

這裏是詞法分析器代碼

%{ 
#include"y.tab.h" 
/*lexer for scanning nested while loops*/ 
%} 

%% 
[\t ] ; /*ignore white spaces*/ 

"while" {return WHILE;} 

[a-zA-Z]+ {return VAR;} 

[0-9]+  {return NUMBER;} 

'$' {return 0;} 

'\n' {return '\n' ;} 

.  {return yytext[0];} 
%% 

VAR是隻ASCII字符變量名和WHILE是while.type不考慮對變量賦值

+1

爲什麼在文法中換行符?詞法分析器應該處理這些。 – EJP

+0

我認爲跟蹤行號等事情可能更容易,如果我通過'\ n',因爲它來自詞法分析器。我曾嘗試刪除'\ n'但我看到有任何改進 – programer8

+1

您的語法預期換行符,但是你的詞法分析器永遠不會返回任何結果,所以這總會給出一個語法錯誤。修復這個問題(或者將它們從語法中刪除或者將它們添加到詞法分析器中)並且工作正常 - 儘管如果您將它們留在其中,它們對於它們非常敏感,而且它們完全位於正確的位置和其他地方。 –

回答

1

你似乎問題的關鍵字具有空循環體,而不是嵌套循環。正如所寫,您的語法在while循環體中至少需要一條語句。您可以通過允許空語句列表來解決這個問題:

statement_list: /* empty */ 
       | statement_list statement '\n' 
       ; 

您還會詢問有關使換行符可選的問題。最簡單的方法是讓詞法分析器簡單地放棄換行符(如空格)而不是返回它們。然後在語法中擺脫換行符,並且換行符可以出現在任何兩個令牌之間,並且將被忽略。

如果你真的必須有換行符語法出於某種原因,你可以添加如下規則:

opt_newlines: /* empty */ | opt_newlines '\n' ; 

,然後無論你想允許換行符(更換使用此規則的所有文字'\n'在你的語法。)但是,你必須小心,不要多餘地使用它。如果你這樣做:

statement_list: /* empty */ 
       | statement_list statement opt_newlines 
       ; 

while_stmt opt_newlines '{' opt_newlines statement_list opt_newlines '}' 

你會得到轉變/減少}前衝突,換行符循環可能在同時opt_newlinesstatement_listopt_newlines的任一部分。通過刪除多餘的opt_newlines來處理這種衝突非常容易。