2014-05-07 169 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来处理这种冲突非常容易。