【问题标题】:Syntax Error in compiler made with flex and bison使用 flex 和 bison 生成的编译器中的语法错误
【发布时间】:2020-01-25 15:59:08
【问题描述】:

首先,我对 flex 和 bison 很陌生,我似乎真的无法解决这个问题。

我已经创建了 flex 和 bison 文件,编译工作正常这里是我的 flex 和 bison 文件

(ps cmets 是法语) 弹性:

%{
// Définitions en language C
#include"minilang.tab.h"
extern int yylval;
extern int nbrligne;
%}

    // les définitions des expressions régulières

    /*
    Définitions de la partie 
    "Liste Declarations" du language MiniLang
    qui inclut les déclarations du language Minilang
    */

chiffre [0-9]
vide [ \t]+|" "+
saut_ligne [\n]+

    // les Nombres (valeurs)
integer [- | +]?([1-9][0-9]*|0)
float [- | +]?([1-9][0-9]*|0)\.[0-9]*[1-9]
bool ("true"|"false"|"TRUE"|"FALSE")
constant integer|float

    // Définitions
varint "INT"|"int"
varfloat "FLOAT"|"float"
varbool "bool"|"BOOL"
const "CONST"|"const"
comment "{"[^}]*"}"

    // Déclarations des éléments du language

    // IDF à revoir
idf ([A-Z]([_]?[a-z0-9])*){1,11}
affectation "="
semicolon ";"
vg ","
plus "++"
minus "--"
beginmc "begin"|"BEGIN"
end "end"|"END"

    /*
    Définitions de la partie 
    "List Instructions" du language MiniLang
    qui inclut les instructions du language Minilang
    */

    // Affectation
op "+"|"-"|"*"|"/"|"&&"|"||"

    // Condition if
if "if"|"IF"|"If"
comp "=="|"<"|"<="|"<>"|">"|">="

    // For loop
for "for"|"FOR"

    // Common
paropen "("
parclose ")"
curlopen "{"
curlclose "}"

%%
    // Expression Régulière { Action C}
{chiffre} {return token_chiffre;}
{vide}
{saut_ligne} {nbrligne++;}
{integer} { yylval = atoi(yytext); return token_integer;}
{float} { yylval = atof(yytext); return token_float;}
{bool} {return token_bool;}
{varint} {return token_varint;}
{varfloat} {return token_varfloat;}
{varbool} {return token_varbool;}
{const} {return token_const;}
{comment} {return token_comment;}

{idf} {return token_idf;}

{affectation} {return token_affectation;}
{semicolon} {return token_semicolon;}
{vg} {return token_vg;}
{plus} {return token_plus;}
{minus} {return token_minus;}
{beginmc} {return token_begin;}
{end} {return token_end;}
{op} {return token_op;}
{if} {return token_if;}
{comp} {return token_comp;}
{for} {return token_for;}
{paropen} {return token_paropen;}
{parclose} {return token_parclose;}
{curlopen} {return token_curlopen;}
{curlclose} {return token_curlclose;}
{constant} {return token_constant;}
. {printf("\nErreur lexicale a la ligne %d ",nbrligne);}
%%

和野牛:

%{
#include <stdio.h>
#include<stdlib.h>

int nbrligne=0;
int yylex();
void yyerror(const char *s);
%}

// Token definitions
%token token_chiffre
%token token_vide
%token token_integer
%token token_float
%token token_bool
%token token_varint
%token token_varfloat
%token token_varbool
%token token_const
%token token_comment
%token token_idf
%token token_affectation
%token token_semicolon
%token token_vg
%token token_plus
%token token_minus
%token token_begin
%token token_end
%token token_op
%token token_if
%token token_comp
%token token_for
%token token_paropen
%token token_parclose
%token token_curlopen
%token token_curlclose
%token token_constant

%%

Prog: DecList token_begin InstList token_end|;

DecList: Declaration DecList|Declaration | token_comment DecList | token_comment;

Declaration: ConstIntDec | ConstFloatDec | ConstBoolDec | IntDec | FloatDec | BoolDec;

ConstIntDec: token_const token_varint MultiIdfInt token_semicolon;

ConstFloatDec: token_const token_varfloat MultiIdfFloat token_semicolon;

ConstBoolDec: token_const token_varbool MultiIdfBool token_semicolon;

IntDec: token_varint MultiIdfInt token_semicolon;
FloatDec: token_varfloat MultiIdfFloat token_semicolon;
BoolDec: token_varbool MultiIdfBool token_semicolon;

MultiIdfInt: token_idf token_vg MultiIdfInt | token_idf | token_idf token_affectation token_integer MultiIdfInt ;

MultiIdfFloat: token_idf token_vg MultiIdfFloat | token_idf | token_idf token_affectation token_integer MultiIdfFloat ;

MultiIdfBool: token_idf token_vg MultiIdfBool | token_idf | token_idf token_affectation token_integer MultiIdfBool ;


InstList: Instruction InstList | Instruction | token_comment InstList | token_comment;

Instruction: Boucle | Affectation | Condition;

Affectation: token_idf token_affectation Exp token_semicolon | Incrementation;

Incrementation: token_constant token_plus | token_constant token_minus;

Exp: token_idf token_op Exp | token_idf | ExpConst;

ExpConst: token_integer token_op ExpConst | token_float token_op ExpConst | token_bool token_op ExpConst 
|   token_bool 
|   token_constant;

Condition: token_if token_paropen ExpCond token_parclose token_curlopen InstList token_curlclose;

ExpCond: token_idf token_comp token_idf 
|   token_idf token_comp token_constant
|   token_idf token_comp token_bool
|   token_constant token_comp token_idf
|   token_bool token_comp token_idf
|   token_constant token_comp token_constant
|   token_bool;

Boucle: token_for token_paropen Affectation token_vg ExpCond token_vg Incrementation token_parclose token_curlopen InstList token_curlclose;









%%

#include"lex.yy.c"
int main() {
    yyparse();
    return yylex();
}

void yyerror(const char *s){ printf("\nERROR %d\n",nbrligne); }
int yywrap(){ return 1; }

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

这是我运行的命令来编译它们并执行编译器

flex minilang.l
bison -d minilang.y
gcc -o compiler minilang.tab.c

test.minilang 是我创建的一个文件,它应该是这个编译器应该解释的相同语言,这里是他的内容

int K_ms;
BEGIN
K_ms=16;
END

此代码产生的错误是“ERROR 1”,这意味着它发生在第一行,我不明白代码中的错误在哪里 语言应该是这样的:

// List of Variable Declarations
BEGIN
// List of Instructions
END

【问题讨论】:

  • 您的vide 规则包含冗余。您不应将 cmets 返回给解析器。将它们视为空白,不要在作品中提及它们。
  • 而且你不应该这样实现你的标识符长度。否则,您会将一个过长的标识符视为两个相邻的标识符,这只会使用户感到困惑,并产生解析错误。您应该在操作代码中进行长度检查。
  • 我现在可以看到将 cmets 发送到解析器是多么不正常,可以解决这个问题,但是“vide”是空格,我猜我也不应该将它发送到解析器。对吗?
  • 关于标识符长度,我想你的意思是告诉我应该不带长度检查的情况下发送给bison,然后处理长度问题
  • 您可以在 Flex 操作中检查长度(请参阅 yyleng)。他的意思是你不应该试图用一种模式来限制它。

标签: c syntax compiler-construction bison flex-lexer


【解决方案1】:

我现在不在电脑前,所以我要回答一个稍微不同的问题:“如何调试我的解析器?”

其中很多只是常识,适用于您不熟悉的任何工具或库的使用。但是 Flex 和 Bison 也有一些非常有用的功能。

所以我们可以从最明显的建议开始:将文档放在手边。如果您使用的是类似 unix 的操作系统,那么您很可能确实在您的机器上安装了它。正确的 flex 和 bison 安装应该包括使用 info 工具所需的文件。所以你可以尝试输入

info flex # or info bison

然后看看这是否会给你手册。如果没有,您可以在线阅读相同的文档(尽管确保您的 flex/bison 版本匹配)。您可以在

找到它们

这两本手册都有调试部分。

下一个一般性建议:从小处着手,逐步提升。不要用你不熟悉的工具写几百行代码,然后才开始测试。从可以测试的最小部分开始,并在添加更多复杂性之前对其进行测试。这不仅可以帮助您解决自己的问题;当您需要寻求帮助时,它还将帮助您描述您的问题。

在解析器的情况下,如何从小处着手是很清楚的:从词法分析器开始,并确保它将您的输入拆分为语法所期望的标记。

如果您打算将 Flex 与 Bison 一起使用,则需要编写 Bison 文件的一小部分:刚好足以让 Bison 生成头文件。 Flex 扫描器需要这个头文件,因为它定义了您将返回给解析器的enum 常量,以及声明语义类型YYSTYPE 和变量yylval,用于传达每个令牌的语义值。 (Bison 手册中有一整章是关于语义值的,它解释了如何声明和使用标记值。)

您可以使用 Flex 的 -d 标志轻松测试您的词法分析器,这将导致生成的扫描器打印每个匹配模式的调试信息(无论扫描器是否返回令牌)。您可以使用-lfl 编译扫描仪;这个库包含一个简单的main,它只是重复调用扫描程序直到它报告 EOF。

您绝对应该执行此步骤,因为您的 Flex 扫描仪有几个与您的问题无关但会在以后引起问题的错误。您需要参考 Flex 手册中有关模式的章节。

一旦您的扫描仪开始工作,您就可以开始使用您的解析器了。与 Flex 一样,Bison 提供了一种调试机制,这将被证明是非常有用的。使用它只需要非常小的改动:

  • 首先,将-t(跟踪)标志添加到您的 Bison 调用中。这将包括生成调试跟踪的代码。但是您仍然需要启动跟踪。

  • 在您调用yyparse 之前,将以下内容添加到您的main() 函数中:

    #if YYDEBUG
      yydebug = 1;
    #endif
    

    预处理器测试是必要的,因为除非使用 -t 标志生成解析器,否则 yydebug 不存在。您可能希望在命令行标志或环境变量上设置 yydebug 条件,这样您就可以在不重新编译的情况下打开或关闭调试。

Bison 调试信息一开始可能有点让人不知所措,但并没有那么复杂。将状态机放在手边会有所帮助;如果您使用-v 标志,Bison 会生成一个文本版本。 (它也可以用Graphviz画出状态机,但是除了只有四五个产生式的玩具语法之外,图形基本无法使用。)

【讨论】:

  • 是的,我正在使用 Linux。将尝试以更有条理的方式阅读文档。感谢调试提示
  • 那是虚假的经济。如果您必须快速完成任务,请快速完成一些任务,然后快速添加小块直到完成。这将比您当前的方法快得多。系统化,您将始终知道要关注什么来修复错误。这可能比你在编译器类中学到的任何东西都更有用。
  • 从现在开始会考虑这个计划 谢谢你的建议 rici
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-21
相关资源
最近更新 更多