Yacc 的语法错误,即使语法是每个语法

Syntax error by Yacc even though the syntax is per grammar

我的 yacc 解析器显示语法错误,即使语法符合语法。 我的 Yacc 代码:

%{
    void yyerror (char *s);
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    int symbols[100];
    int yylex();
    int symbolVal(char symbol);
    void updateSymbolVal(char symbol,int val);
%}

%union {int num; char id;}
%start line
%token WHILE
%token lt
%token gt
%token exit_command
%token <num> number
%token <id> identifier
%type <num> line exp term
%type <id> assignment
%type <num> condition


%%


line:   assignment          {;} 
        |line assignment    {;}
        |exit_command       {exit(EXIT_SUCCESS);}
        |line exit_command  {exit(EXIT_SUCCESS);}
        |whileLoop          {;}
        |condition          {;}
        ;

whileLoop: WHILE '(' condition ')' '{' assignment '}'          {printf("while loop condition var:%d\n",);}
         ;


assignment  : identifier '=' exp {updateSymbolVal(,);}
            ;

exp         :   term                {$$ = ;}
            |   exp '+' term        {$$ =  + ;}
            |   exp '-' term        {$$ =  - ;}
            ;

term        :   number              {$$ = ;}
            |   identifier          {$$ = symbolVal();}
            ;

condition  :  identifier cond_op identifier     {$$ = ;}
              |identifier cond_op number        {$$ = ;}
              ;


cond_op   :  lt
            | gt
            ;

%%

int computeSymbolIndex(char token){
    int idx = -1;
    if(islower(token)){
        idx = token - 'a' +26;
    }
    else if(isupper(token)){
        idx = token - 'A' + 26;
    }
    return idx;
}

int symbolVal(char symbol){
    int bucket = computeSymbolIndex(symbol);
    return symbols[bucket];
}

void updateSymbolVal(char symbol, int val){
    int bucket = computeSymbolIndex(symbol);
    symbols[bucket] = val;
}

int main(void){
    int i;
    for(i=0;i<52;i++){
        symbols[i] = 0;
    }

    return yyparse();
}

void yyerror (char *s){fprintf (stderr, "%s\n",s);}

我的 Lex 代码:

%{
    #include "y.tab.h"
%}

%%

"while"         {printf("while\n"); return WHILE;}
"exit"          {return exit_command;}
[a-zA-Z]        {yylval.id = yytext[0]; return identifier;}
[0-9]+          {yylval.num = atoi(yytext); return number;}
"<"             {return lt;}
">"             {return gt;}
[ \t\n]         ;
[-+=;]          {return yytext[0];}
.               ;

%%
int yywrap (void) 
{
    return 1;
}

显示语法错误的示例文本:

while(i>0){i = i-1}

“while”按照 lex 打印,但下一行输出是“Syntax Error”。

甚至连“while 循环条件变量”都没有打印出来。

语法错误尤其是while循环。

条件语句赋值等所有其他事情似乎工作正常。

为什么会这样?

您有一个词法分析器后备规则,它会自动丢弃无法识别的字符:

.               ;

正如您刚刚发现的那样,这确实不是一个好主意。在这种情况下,没有其他规则识别 (),因此它们被上述规则忽略。但是,您的解析器需要一个括号。它没有得到一个,所以它报告一个语法错误。

更好的是以下后备规则,它可以替代前面的规则:

   /* [-+=;]          {return yytext[0];} */ /* now redundant*/
.               {return yytext[0];}

这接受词法分析器中的任何字符。但是,大多数字符在语法中的任何地方都不会用作字符文字,因此它们将被解析器视为无效标记,从而导致语法错误。

您可以通过在您的 lex 后备规则中写入错误来获得更准确的错误消息,但是您需要确保识别所有 vslid 字符:

[-+=;(){}]      {return yytext[0];}
.               {return yytext[0];}

就个人而言,我会将 <> 添加到该列表中,而不是使用专门的规则(和不必要的标记名称。)