Bison 解析器总是打印 "syntax error"

Bison parser always prints "syntax error"

我正在尝试构建一个 3 地址代码生成器,它将生成:

input:x=a+3*(b/7)


output: t1=b/7
t2=3*t1
t3=a+t2
x=t3

无论我输入什么,输出都是"syntax error"。

我正在使用 Windows 10.

Yacc 代码:

   %{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define YYDEBUG 1

int yylex(void);
int t_count = 1;

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

char * generateToken(int i)
{

char* ch=(char*)malloc(sizeof(char)*5);

sprintf(ch,"t%d",i++);

return ch;
}

%}

%union { double dval; char ivar[50]; }
%token <ivar> NUMBER
%token  <ivar> NAME

%type <ivar> expr
%type <ivar> term
%left '+' '-'
%left '*' '/'
%left '(' ')'
%right '='
%%
program:
    line            {
                            }
    | program line                  {
                            }
    ;
line:
    expr    '\n'            {   
                                t_count =1; 
                            }
    | NAME '=' expr '\n'    {   

                                printf("%s = %s", ,);
                                t_count=1;
                            }
    ;
expr:
    expr '+' expr           { 


                                strcpy($$,generateToken(t_count));

                                printf("%s = %s + %s",$$,,);

                            }
    | expr '-' expr         { 


                                    strcpy($$,generateToken(t_count));
                                printf("%s = %s - %s",$$,,);


                            }

    | expr '*' expr         { 

                                    strcpy($$,generateToken(t_count));
                                printf("%s = %s * %s",$$,,);

                            }
    | expr '/' expr         { 

                                    strcpy($$,generateToken(t_count));
                                printf("%s = %s / %s",$$,,);

                            }
    | term                  {               
                                strcpy($$, );
                            }
    | '(' expr ')'      {

                                strcpy($$,generateToken(t_count));
                                printf("%s =( %s )" ,$$,);

                            }
    ;
term:

    NAME                    { 

                                strcpy($$, );
                            }
    | NUMBER                {   
                                strcpy($$, );

                            }
    ;
%%

int main(void)
{
    if (getenv("YYDEBUG")) yydebug = 1;


    yyparse();

    return 0;
}

莱克斯代码:

%option noyywrap
               %{
               #include <stdlib.h>
               #include <stdio.h>
               #include <string.h>
               #include "threeAdd.tab.h"

               void yyerror(char*);
               extern YYSTYPE yylval;
               %}
               NAME [a-zA-Z]
               DIGIT  [0-9]+
               NUMBER [-]?{DIGIT}+(\.{DIGIT}+)?

               %%
               [ \t]+    { }
               {NUMBER}
                    {


                    strcpy(yylval.ivar,yytext);
                    return *yylval.ivar;
                     }
               "+"  {
                        return *yytext;
                     }
               "-" {
                        return *yytext;
                     }
               "*"  {
                        return *yytext;
                     }
               "/"  {
                        return *yytext;
                     }
               "="   {
                        return *yytext;
                     }       
               "("   {
                        return *yytext;
                     }
               ")"   {
                        return *yytext;
                     }
               {NAME}    {


                        strcpy(yylval.ivar,yytext);
                        return *yylval.ivar;
                    }
               "\n"          {
                        return *yytext;
                     }
               exit     {
                        return 0;
                     }

               .        {
                        char msg[25];
                        sprintf(msg," <%s>","invalid character",yytext);
                        yyerror(msg);
                     }


               %%

示例构建 & 运行:

基本问题是您在 yacc 文件中对标记使用双引号(" -- 字符串)(没有为它们定义任何代码,因此它们没有用),并且 returning lex 文件中的单个字符标记。因此,none 个标记将在您的解析器中被识别。

将 yacc 文件中所有单字符标记上的所有 " 字符替换为 ' 字符(因此 "+" 变为 '+'"\n"变成 '\n').

一旦你解决了这个问题,你就会遇到另一个问题:你的 {DIGITS}+{NAME} 的 lex 规则没有 return 一个标记,所以这个标记将被忽略(导致语法错误)

对于调试一般的解析器问题,通常值得在调用 yyparse 之前使用 -DYYDEBUG 进行编译并将 yydebug = 1; 粘贴到 main 中,这将导致解析器打印所见标记的踪迹和状态访问过。我经常放

if (getenv("YYDEBUG")) yydebug = 1;

进入 main 并把它留在那里——这样通常不会启用调试,但是如果你在 运行 你的程序之前设置环境变量 YYDEBUG=1,你会看到调试跟踪(无需重新编译)


为了 return 一个标记,你的词法分析器规则需要 return 这个标记。所以 NUMBER 的词法分析器规则应该是:

{NUMBER} {
            strcpy(yylval.ivar,yytext);
            return NUMBER;
         }

NAME 类似。请注意,代码块的开头 { 必须与模式在同一行——如果它在不同的行,则不会与模式相关联。