用 flex 和 bison 制作的编译器中的语法错误 [英] Syntax Error in compiler made with flex and bison

查看:78
本文介绍了用 flex 和 bison 制作的编译器中的语法错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

First of all, I'm very new to flex and bison and I really can't seem to solve this problem.

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

I have created both flex and bison files and it the compilation works fine here are both my flex and bison files

(ps 评论是法语)弹性:

(ps the comments are in french) Flex:

%{
// 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;
// }

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

And here are the commands I ran to compile both of them and execute the compiler

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

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

test.minilang is a file that I created that is supposed to be the same language this compiler is supposed to interpret here are his contents

int K_ms;
BEGIN
K_ms=16;
END

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

the error produced with this code is "ERROR 1" which means it happened on the first line and I don't understand where is the error in my code the language is supposed to look like this:

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

推荐答案

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

I'm not in front of a computer right now, so I'm going to answer a slightly different question: "How can I debug my parser?"

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

A lot of this is just common sense, and would apply to the use of any tool or library that you are not familiar with. But there are also some features of Flex and Bison which can be really useful.

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

So we can start with the most obvious advice: have the documentation easily at hand. It's quite possible that you actually do have it on your machine, if you're using a unix-like operating system. A correct flex and bison installation should include the files necessary to use the info tool. So you could try typing

info flex # or info bison

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

And see if that gives you the manual. If not, you can read the same docs online (although make sure your flex/bison version matches). You'll find them at

这两本手册都有关于调试的部分.

Both of these manuals have sections on debugging.

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

Next general advice: start small, and work your way up. Don't write several hundred lines of code using a tool you're not familiar with, and only then start testing. Start with the smallest piece which does something you can test, and test it before adding more complication. Not only will this help you solve your own problems; it will also help you describe your problem when you need to ask for help.

就解析器而言,很清楚如何从小处着手:从词法分析器开始,并确保它按照语法预期将您的输入拆分为标记.

In the case of a parser, it's clear how to start small: start with the lexer and make sure that it splits your input into tokens as your grammar will expect.

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

If you're going to be using Flex with Bison, you will need to write a small part of your Bison file: just enough for Bison to produce a header file. Flex scanners require this header file because it defines the enum constants you will be returning to the parser, as well as declaring the semantic type YYSTYPE and the variable yylval, used to communicate each token's semantic value. (There's a whole chapter on semantic values in the Bison manual which explains how to declare and use token values.)

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

You can easily test your lexer by using the -d flag to Flex, which will cause the generated scanner to print debugging information for each pattern matched (whether or not the scanner returns a token). You can compile the scanner with -lfl; this library includes a simple main which just calls the scanner repeatedly until it reports EOF.

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

You should definitely do this step, because your Flex scanner has several bugs which are not related to your question but which will cause problems later. You will want to refer to the chapter on Patterns in the Flex manual.

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

Once your scanner is working, you can start working on your parser. Like Flex, Bison offers a debugging mechanism which will prove to be very useful. Only very minor changes are needed to use it:

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

  • First, add the -t (trace) flag to your Bison invocation. This will include the code to generating debugging traces. But you still need to start the traces.

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

Add the following to your main() function before you call yyparse:

#if YYDEBUG
  yydebug = 1;
#endif

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

The preprocessor test is necessary because yydebug doesn't exist unless the parser was generated with the -t flag. You might want to make setting yydebug conditional on a command-line flag or environment variable so you can turn debugging on or off without recompiling.

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

The Bison debugging information can be a bit overwhelming at first, but it's not that complicated. It will help to have the state machine handy; Bison generates a text version if you use the -v flag. (It also can draw the state machine using Graphviz, but aside from toy grammars with only four or five productions, the graphic is basically unusable.)

这篇关于用 flex 和 bison 制作的编译器中的语法错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆