查找 Flex Yacc 中发生语法错误的位置

Find Where Syntax Error in Flex Yacc Happened

我对 lex 和 yacc 还很陌生。

我正在设计一个可以生成三地址代码的编译器。

如何找到代码中发生语法错误的位置?

进入后:

flex lexer.l
bison -dy parser.y
gcc lex.yy.c y.tab.c -o program.exe

我试试这个输入:

{ int abc = 234 ; }

然后它给我语法错误!

我该如何解决?

这是我的词法分析器

lexer.l:

%{

#include "y.tab.h"
#include <string.h>
int yyerror(char *errormsg);

%}

letter  [a-zA-z]
digit   [0-9]
id      {letter}({letter}|{digit})*
ws      [ \t]


%%
{ws}        ;
\{          { return 300; }
\}          { return 301; }
\;          { return SEMICOLON; }
"if"        { return IF; }
"int"       { return INT; }
"float"     { return FLOAT; }
"char"      { return CHAR; }
\=          { return ASSIGN; }      
{id}        {strcpy(yylval.str,yytext) ; return ID; }
{digit}+    {yylval.ival=atoi(yytext); return NUMBER; }
.           {yyerror("Invalid Command");}
%%



int main(void)
{
   yyparse();
   printf("DONE");
   return 0;
}

int yywrap(void)
{
   return 0;
}

int yyerror(char *errormsg)
{
    fprintf(stderr, "hey!%s\n", errormsg);
    exit(1);
}

这是我的解析器

parser.y:

%{

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int yylex(void);
int yyerror(const char *s);

%}


%union{int ival; double dval; char str[120]; }

%token INT ASSIGN NUMBER IF SEMICOLON
%token FLOAT
%token ID CHAR

%%

Program: 
        Block
        ;

Block:
        '{' Stmts '}'
        ;

Stmts:
        Stmts Stmt
        | Stmt
        ;

Stmt:
        Block
        |IfStmt
        |AssignStmt
        |DeclStmt
        ;


IfStmt:
        IF '(' Expr ')' Stmt  { printf("if found"); }
        ;


AssignStmt:     
        Type ID ASSIGN Expr SEMICOLON { printf("int found!"); }
        ;

DeclStmt:
        Type ID SEMICOLON
        ;


Type:
        INT
        |FLOAT
        |CHAR
        ;


Expr:
    NUMBER
    ;

你可以通过-DYYDEBUG=1':

编译让野牛输出它正在做的事情
gcc -DYYDEBUG=1 lex.yy.c y.tab.c -o program.exe

然后 运行 将 yydebug 全局变量设置为真值:

int main(void)
{

    #ifdef YYDEBUG
    yydebug = 1;
    #endif
   yyparse();
   printf("DONE");
   return 0;
}

为您的项目执行此操作,产量

Starting parse
Entering state 0
Reading a token: Next token is token $undefined ()
hey!syntax error

IOW,词法分析器返回的第一个标记无法被解析器识别。

您为 { 返回 300,但解析器期望 '{',因此只需修复词法分析器规则:

//WRONG
\{          { return 300; }
\}          { return 301; }

//OK
 \{          { return '{'; }
 \}          { return '}'; }

然后你得到一个完成的解析,尽管它挂起。

挂起是由您在 yywrap 中返回 0 引起的。将其更改为 1 将删除它。

在尝试找出 Bison 的语法错误时,您要做的第一件事是将 %define parse.error verbose 选项添加到您的 Bison 文件中。这会将错误消息更改为比“语法错误”更有帮助的内容。请注意,这是 Bison 特有的功能,因此您需要在调用 Bison 时删除 -y 标志。这样做,错误消息将更改为:

syntax error, unexpected $undefined, expecting '{'

所以它告诉你它得到了一个 $undefined 而它期望 {。那么什么是 $undefined?这就是 Bison 显示它不知道其名称的任何令牌的方式。如果令牌是 ASCII 中的整数,它将显示为 'x'(而不是 x,它将是给定的 ASCII 字符)。如果令牌已使用 %token 定义,它将显示为与该 %token 声明关联的名称。只有当两者都不是时,你才会得到 $undefined.

因此您的词法分析器 return 既不是 ASCII 字符也不是定义的标记。所以让我们看看你的词法分析器是否有类似的东西,果然:

\{          { return 300; }
\}          { return 301; }

当你的词法分析器看到大括号时,它会分别 return 300 或 301。这些既不是字符也不是使用 %token 定义的标记,因此它们对 Bison 没有任何意义。

因为你的解析器希望看到 '{''}',上面应该分别说 return '{';return '}';(或者 return yytext[0]; 在这两种情况下,如果你比较喜欢)。或者,您可以在解析器中定义 %token LBRACE RBRACE,在 Block 规则中使用它们代替 '{''}',在词法分析器中使用 return。无论哪种方式,你绝对不应该 return 词法分析器中的任意整数。


您还需要 return 1 而不是 yywrap 中的 0 或使用 noyywrap 选项完全删除它。返回 0 会使词法分析器在到达文件末尾后等待进一步的输入。