首先,我对flex和bison非常陌生,我似乎真的无法解决这个问题。
我已经创建了flex和bison文件,并且编译正常,这里是我的flex和bison文件
(ps注释为法语)弹性:
%{
// 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
您的问题在flex中,在这里:
idf ([A-Z]([_]?[a-z0-9])*){1,11}
您需要将其更改为
idf ([A-Z]([_]?[a-z0-9])*)
我现在不在电脑前,所以我要回答一个稍有不同的问题:“我如何调试解析器?”
其中很多只是常识,适用于您不熟悉的任何工具或库的使用。但是Flex和Bison也有一些功能确实有用。
因此,我们可以从最明显的建议开始:轻松获取文档。如果您使用的是类似Unix的操作系统,则很可能实际上已经在计算机上安装了它。正确的flex和bison安装应包括使用info
工具所需的文件。因此,您可以尝试输入
info flex # or info bison
然后看看是否能给您手册。如果没有,您可以在线阅读相同的文档(尽管请确保您的flex / bison版本匹配)。您可以在[]找到它们
这两个手册都有调试部分。
[下一条一般建议:从小处着手,然后逐步提高。不要使用您不熟悉的工具编写数百行代码,然后才开始测试。从最小的东西开始,您可以做一些可以测试的事情,并在增加更多复杂性之前对其进行测试。这不仅可以帮助您解决自己的问题;当您需要帮助时,它还将帮助您描述问题。
在解析器的情况下,很清楚如何从小处开始:从词法分析器开始,并确保将其输入内容按语法期望的那样拆分为标记。
[如果要与Bison一起使用Flex,则将需要编写Bison文件的一小部分:刚好足以使Bison生成头文件。 Flex扫描程序需要此头文件,因为它定义了将要返回到解析器的enum
常量,并声明了用于传递每个令牌的语义值的语义类型YYSTYPE
和变量yylval
。 (Bison手册中有一整章关于语义值的内容,解释了如何声明和使用令牌值。)
您可以通过在Flex上使用-d
标志来轻松测试词法分析器,这将使生成的扫描程序为每个匹配的模式打印调试信息(无论扫描程序是否返回令牌)。您可以使用-lfl
编译扫描器;该库包含一个简单的main
,它仅反复调用扫描程序,直到报告EOF。
您绝对应该执行此步骤,因为您的Flex扫描仪有一些错误与您的问题无关,但稍后会引起问题。您可能要参考Flex手册中有关“图案”的章节。
一旦扫描仪开始工作,您就可以开始使用解析器了。像Flex一样,Bison提供了一种调试机制,这将非常有用。只需要很小的改动就可以使用它:
首先,在您的Bison调用中添加-t
(跟踪)标志。这将包括生成调试跟踪的代码。但是您仍然需要启动跟踪。
在调用main()
之前,将以下内容添加到yyparse
函数中:
#if YYDEBUG yydebug = 1; #endif
预处理器测试是必要的,因为除非使用
yydebug
标志生成解析器,否则-t
不存在。您可能希望以命令行标志或环境变量为条件设置yydebug
,以便无需重新编译即可打开或关闭调试。
Bison调试信息起初可能有点不知所措,但这并不复杂。方便使用状态机;如果使用-v
标志,则Bison会生成文本版本。 (它也可以使用Graphviz绘制状态机,但是除了玩具语法只有四个或五个产品外,该图形基本上是不可用的。)