【问题标题】:Find Where Syntax Error in Flex Yacc Happened查找 Flex Yacc 中发生语法错误的位置
【发布时间】:2019-12-24 10:04:36
【问题描述】:

我对 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
    ;

【问题讨论】:

  • 什么是语法错误?写在帖子里
  • 语法错误是“语法错误”。这就是使用默认选项在 Bison 中出现的语法错误。

标签: compiler-construction bison yacc lex


【解决方案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

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

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

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

由于您的解析器希望看到'{''}',因此上面应该分别显示return '{';return '}';(如果您愿意,可以在这两种情况下使用return yytext[0];)。或者,您可以在解析器中定义%token LBRACE RBRACE,在Block 规则中使用它们而不是'{''}',然后在词法分析器中返回它们。无论哪种方式,你绝对不应该在你的词法分析器中返回任意整数。


您还希望在 yywrap 中返回 1 而不是 0,或者使用 noyywrap 选项完全摆脱它。返回 0 使词法分析器在到达文件末尾后等待进一步的输入。

【讨论】:

    【解决方案2】:

    您可以通过使用-DYYDEBUG=1' 编译来让bison 输出它正在执行的操作:

    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 将删除它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      • 2014-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-17
      • 2023-03-19
      相关资源
      最近更新 更多