我在flex中编写了以下代码片段。我需要显示以下消息:
{printf("\n%-20s%-30s%-10s\n", "Lexeme", "Unite lexicale", "Indice");}
用户输入后的第一件事,我试图找到一个解决方案,但似乎没什么用。
%{
int i=1;
%}
lettre [a-zA-Z]+
nombre_entier (\+|\-)?[0-9]+
nombre_reel (\+|\-)?[0-9]+\.[0-9]+((e|E)(\-|\+)?[0-9]+)?
id {lettre}({lettre}|[0-9])*
%%
\$ { exit(0);}
[ \t]+ {/*ignorer*/}
\n {i=1;}
ENTIER|REEL {printf("%-20s%-30s%-10d\n",yytext, "Mot_cle", i++);
printf("-----------------------------------------------------\n");}
{id} {printf("%-20s%-30s%-10d\n",yytext, "ID", i++);
printf("------------------------------------------------------\n");}
{nombre_entier} {printf("%-20s%-30s%-10d\n",yytext, "nombre entier", i++);
printf("------------------------------------------------------\n");}
{nombre_reel} {printf("%-20s%-30s%-10d\n",yytext, "nombre reel", i++);
printf("------------------------------------------------------\n");}
\( {printf("%-20s%-30s%-10d\n",yytext, "parenthese ouvrante", i++);
printf("------------------------------------------------------\n");}
")" {printf("%-20s%-30s%-10d\n",yytext, "parenthese fermante", i++);
printf("------------------------------------------------------\n");}
"+"|"-"|"*"|"/" {printf("%-20s%-30s%-10d\n",yytext, "operateur arithmetique", i++);
printf("------------------------------------------------------\n");}
"=" {printf("%-20s%-30s%-10d\n",yytext, "operateur d'affectation", i++);
printf("------------------------------------------------------\n");}
"," {printf("%-20s%-30s%-10d\n",yytext, "Virgule", i++);
printf("------------------------------------------------------\n");}
";" {printf("%-20s%-30s%-10d\n",yytext, "Point virgule", i++);
printf("------------------------------------------------------\n");}
. {printf("%-20s%-30s%-10d\n",yytext, "caractere inconnu", i++);
printf("------------------------------------------------------\n");}
%%
int main(){
printf("Entrez le texte a analyser : \n");
yylex();
return 0;
}
int yywrap(){
return 1;
}
请帮忙。
答案 0 :(得分:2)
更清洁的解决方案是以预期的方式使用flex
扫描程序,即连续将词法标记返回给其调用者,每次调用一个标记。
这意味着您需要一些方法让扫描仪识别它遇到的令牌类型。通常,您将使用枚举(或者更传统的是#define
s的集合),这些枚举放置在头文件中,扫描器及其调用者都可以包含该头文件。如果您使用解析器生成器(如yacc或bison),则会自动为您生成此标头。
您还需要一些方法让扫描仪返回"语义值"令牌。在这个简单的情况下,这是没有必要的,因为你不会对令牌的值做任何事情,除了立即打印出来。这使得可以使用yytext
全局变量(如果您的扫描程序使用全局变量),但在flex动作之外使用yytext
是一个等待发生的错误,因为yytext
和它指向的缓冲区是扫描仪内部状态的一部分,内容可以并且将在没有警告的情况下改变。你可以在这里拿走它,因为在下次调用yylex
之前没有任何改变。
在实践中,它可能看起来像这样:
enum Token {
T_FIN = 0,
T_MOTCLE,
T_ID,
T_ENTIER,
T_REEL,
T_OUVRANTE,
T_FERMANTE,
T_OPERATEUR,
T_AFFECT,
T_VIRGULE,
T_POINT_VIRGULE,
T_INCONNU
};
const char* decrire(int jeton);
现在,我们还需要一些方法将这些枚举值与人类可读的描述相关联。简单的方法是以与值相同的顺序创建字符串表。在生产代码中,您可能希望选择更易于维护的内容。请记住,令牌代码0通常用于指示输入的结束,因此您需要留出空间。
#include <stdio.h>
#include "tokens.h"
static const char* descriptions = {
"Fin d'entree",
"Mot_cle",
"ID",
"Nombre entier",
"Nombre reel",
"Parenthese ouvrante",
"Parenthese fermante"
"Operateur arithmetique",
"Operateur d'affectation",
"Virgule",
"Point virgule",
"Caractere inconnu"
};
const char* decrire(int jeton) {
if (jeton >= 0 && jeton <= T_INCONNU)
return descriptions[jeton];
else
return "???"; /* This indicates a bug somewhere */
}
现在我们可以为这个词法分析器编写一个非常简单的应用程序,它打印出令牌流:
int main() {
puts("Entrez le texte a analyser : ");
int jeton = yylex();
printf("\n%-20s%-30s%-10s\n", "Lexeme", "Unite lexicale", "Indice");
puts("-----------------------------------------------------");
for (int i = 1; jeton; jeton = yylex();) {
printf("%-20s%-30s%-10d\n", yytext, decrire(jeton), token_count++);
puts("------------------------------------------------------");
}
return 0;
}
最后,有点清理的词法分析器:
%{
#include "tokens.h"
int token_count;
%}
%options noinput nounput noyywrap nodefault
%%
"$" { return T_FIN; }
[ \t]+ { /*ignorer*/ }
\n { token_count = 1; }
ENTIER|REEL { return T_MOTCLE; }
[[:alpha:]][[:alnum:]]* { return T_ID; }
[+-]?[[:digit:]]* { return T_ENTIER; }
[+-]?[[:digit:]]+\.[[:digit:]]+([eE][+-]?[[:digit:]]*)? {
return T_REEL; }
"(" { return T_OUVRANTE; }
")" { return T_FERMANTE; }
[-+*/] { return T_OPERATEUR; }
"=" { return T_AFFECT; }
"," { return T_VIRGULE; }
";" { return T_POINT_VIRGULE; }
. { return T_INCONNU; }
令牌计数的处理(以及没有行计数)不太理想;理想的解决方案是使用标准yylloc
全局(或重入扫描器的参数)来保存位置信息,为该信息添加令牌计数。
答案 1 :(得分:0)
谢谢@DYZ这是我最终做的事情
%{
int i=1,j=0;
#define YY_INPUT(buf,result,max_size) \
{ \
int c = getchar(); \
result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
if(j++ == 0) \
{ \
printf("\n%-20s%-30s%-10s\n", "Lexeme", "Unite lexicale", "Indice"); \
printf("-----------------------------------------------------\n"); \
} \
}
%}