gpt4 book ai didi

bison - 如何使用yacc解析器检测错误行号

转载 作者:行者123 更新时间:2023-12-04 02:22:53 25 4
gpt4 key购买 nike

我们不知道如何在 yacc 解析器中跟踪错误。
我们正在尝试使用 yylineno在我们的 lex 文件中并尝试添加 %option yylineno但它仍然不起作用,我们无法在 yacc 中访问这些变量。

我们想要的只是使用 error 打印出语法错误在 yacc 和行号。

这是我们的 .l文件

%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
int yylineno=1;

%}

%option yylineno

identifier [a-zA-Z_][a-zA-Z0-9_]*
int_constant [0-9]+
delimiter ;

%%

"int" {return INT;}
{int_constant} return INT_CONST;
{identifier} return IDENT;
\= {return ASOP;}
\+ {return PLUS;}
\- {return MINUS;}
\* {return MULT;}
\/ {return DIV;}
\, {return COMMA;}
\( {return OP;} /*OP CP = Opening Closing Parenthesis*/
\) {return CP;}
\[ {return OB;} /*OB CB = Opening Closing Brace*/
\] {return CB;}
\{ {return OCB;} /*OCB CCB = Opening Closing Curly Brace*/
\} {return CCB;}
{delimiter} return DEL;
[ \t]
[\n] {yylineno++;}


%%

现在这是我们的 .y文件
%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"

extern FILE *yyin;

%}

%token INT INT_CONST IDENT ASOP PLUS MINUS MULT DIV DEL COMMA CP CB CCB
%left OP OB OCB


%%

program: program_unit;
program_unit: program_unit component | component
component: var_decl DEL | func_decl DEL | func_defn ;
var_decl: dt list;
dt: INT;
list: list COMMA var | var
| error {printf("before ';' token\n"); yyerrok;}
| error INT_CONST {printf("before numeric constant\n"); yyerrok;};
var: IDENT
|IDENT init;
init: ASOP IDENT init | ASOP expr | ASOP IDENT ;
expr: IDENT op expr | const op expr | const | OP expr CP;
const: INT_CONST;
op: PLUS | MINUS | MULT | DIV;
func_decl: dt mult_func;
mult_func: mult_func COMMA mfunc | sfunc;
mfunc: IDENT OP CP;
sfunc: IDENT OP CP OCB func_body CCB;
func_body: program_unit;

func_defn: dt IDENT OP CP OCB func_body CCB
| IDENT OP CP OCB func_body CCB;

%%

int yyerror(char *s){
extern int yylineno;
fprintf(stderr,"At line %d %s ",s,yylineno);
}

int yywrap(){
return 1;
}

int main(int argc, char *argv[]){
yyin=fopen("test.c","r");
yyparse();
fclose(yyin);
return 0;
}

最佳答案

这些文件存在许多问题,但它们都不会阻止 yylineno从可用于您的野牛生成的解析器。

您对 yyerror 的定义会导致编译时警告。 .或者可能有几个警告。

首先,正确的签名是:

void yyerror(const char *msg);

可以返回 int但从未使用过该值;但是,您对函数的定义刚刚结束,因此编译器会提示没有返回任何值的事实。另外, yyerror通常使用文字字符串参数调用,该参数是不可变的;标准 C 允许将文字字符串传递给参数类型为非常量的函数,但不推荐使用,编译器可能会发出警告。更重要的是,
fprintf(stderr,"At line %d %s ",s,yylineno);

适用于 %d (整数)格式为 s (一个字符串)和 %s (字符串)格式为 yylineno (一个整数);同样,这应该会产生一个编译时警告,如果您忽略该错误,您的程序可能会出现段错误。

最后(与 yylineno 相关),如果您指定 %option yylineno在您的 flex输入(如果你想计算行号,这是个好主意)那么 flex 生成的扫描器将定义和初始化 yylineno并为你数数。所以你对 yylineno 的定义在您的 .l文件将触发编译时错误(重新定义 yylineno )。同样,当您增加 yylineno 时( [\n] {++yylineno;} ) 明确地,你最终会重复计算行数; yylineno将由扫描仪递增,然后通过您的操作再次递增。我的建议:指定 %option yylineno然后让 flex 为你做一切。您只需将其声明为 extern在您的 bison文件(就像你一样)。您只需添加 \n到被忽略的空白字符列表。

一个警告:使用 yylineno直接在 bison意味着您将没有语法错误的确切位置,因为 bison -生成的解析器通常读取一个前瞻标记,并且 yylinenobison 时,将已经更新到此标记末尾的行号注意到语法错误。有时这会产生误导,尤其是在由于缺少 token 而导致语法错误的情况下。

其他一些问题:
  • 使用文字字符标记而不是在 bison 中定义标记名称要好得多(恕我直言)并与您的 flex 协调它们文件。如果你只使用文字字符,那么这两个文件更容易保持同步;语法更易读;你不需要像这样的评论
    /*OP CP = Opening Closing Parenthesis*/

    相反,只需使用 ')'在语法和词法分析器中,您可以执行以下操作:
    [][=+*/,(){}-]  { return yytext[0]; }

    或者您甚至可以在最后使用默认规则:
    .  { return yytext[0]; }
  • 与上述相关,以及我通常选择第二个选项(默认规则)的原因,您的词法分析器没有针对所有可能字符的规则,因此将使用 flex 提供的默认规则。 flex 提供的默认规则是将无效字符回显到 yyout .在实际的编译器中,这永远不是您想要的,结果是输入错误(或扫描程序错误)被默默隐藏。最好使用我上面建议的默认规则,并使用 %option nodefault 保护自己。避免 flex 生成的默认规则。与 %option nodefault , 如果输入不匹配,flex 会给你一个警告;请不要忽略此警告。
  • 关于bison - 如何使用yacc解析器检测错误行号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26211770/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com