用户在 flex 中输入后显示消息
Display message after user input in flex
我有以下用 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;
}
请帮忙。
谢谢@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"); \
} \
}
%}
一个更简洁的解决方案是以预期的方式使用 flex
扫描器,即连续 return 词汇标记给它的调用者,每次调用一个标记。
这意味着您需要一些方法让扫描器识别它遇到的令牌类型。通常,您将使用一个枚举(或者,更传统地说,collection of #define
s),它们被放置在一个 header 文件中,扫描器及其调用者都可以包含该文件.如果您使用 yacc 或 bison 等解析器生成器,此 header 将自动为您生成。
您还需要某种方式让扫描器 return 令牌的“语义值”。在这个简单的例子中,这是没有必要的,因为除了立即打印出来之外,您没有对令牌的值进行任何操作。这使得使用 yytext
全局变量成为可能(如果您的扫描器使用全局变量),但是在 flex 操作之外使用 yytext
是一个等待发生的错误,因为 yytext
和它指向的缓冲区是扫描仪内部状态的一部分,内容可以并且将会在没有警告的情况下发生变化。你可以在这里解决它,因为在下一次调用 yylex
.
之前什么都不会改变
实际上,它可能看起来像这样:
文件:tokens.h
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);
现在,我们还需要一些方法将这些枚举值与 human-readable 描述相关联。简单的方法是按与值相同的顺序制作一个 table 字符串。在生产代码中,您可能希望选择更易于维护的代码。记住token code 0习惯上用来表示输入结束,所以需要留出空间。
文件:tokens.c
#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;
}
最后,有点 cleaned-up 词法分析器:
文件tokens.l
%{
#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
全局(或可重入扫描器的参数)来保存位置信息,并向该信息添加令牌计数。
我有以下用 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;
}
请帮忙。
谢谢@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"); \
} \
}
%}
一个更简洁的解决方案是以预期的方式使用 flex
扫描器,即连续 return 词汇标记给它的调用者,每次调用一个标记。
这意味着您需要一些方法让扫描器识别它遇到的令牌类型。通常,您将使用一个枚举(或者,更传统地说,collection of #define
s),它们被放置在一个 header 文件中,扫描器及其调用者都可以包含该文件.如果您使用 yacc 或 bison 等解析器生成器,此 header 将自动为您生成。
您还需要某种方式让扫描器 return 令牌的“语义值”。在这个简单的例子中,这是没有必要的,因为除了立即打印出来之外,您没有对令牌的值进行任何操作。这使得使用 yytext
全局变量成为可能(如果您的扫描器使用全局变量),但是在 flex 操作之外使用 yytext
是一个等待发生的错误,因为 yytext
和它指向的缓冲区是扫描仪内部状态的一部分,内容可以并且将会在没有警告的情况下发生变化。你可以在这里解决它,因为在下一次调用 yylex
.
实际上,它可能看起来像这样:
文件:tokens.h
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);
现在,我们还需要一些方法将这些枚举值与 human-readable 描述相关联。简单的方法是按与值相同的顺序制作一个 table 字符串。在生产代码中,您可能希望选择更易于维护的代码。记住token code 0习惯上用来表示输入结束,所以需要留出空间。
文件:tokens.c
#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;
}
最后,有点 cleaned-up 词法分析器:
文件tokens.l
%{
#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
全局(或可重入扫描器的参数)来保存位置信息,并向该信息添加令牌计数。