用户在flex中输入后显示消息

时间:2017-01-30 22:49:41

标签: c algorithm bison flex-lexer

我在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;
}

请帮忙。

2 个答案:

答案 0 :(得分:2)

更清洁的解决方案是以预期的方式使用flex扫描程序,即连续将词法标记返回给其调用者,每次调用一个标记。

这意味着您需要一些方法让扫描仪识别它遇到的令牌类型。通常,您将使用枚举(或者更传统的是#define s的集合),这些枚举放置在头文件中,扫描器及其调用者都可以包含该头文件。如果您使用解析器生成器(如yacc或bison),则会自动为您生成此标头。

您还需要一些方法让扫描仪返回"语义值"令牌。在这个简单的情况下,这是没有必要的,因为你不会对令牌的值做任何事情,除了立即打印出来。这使得可以使用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);

现在,我们还需要一些方法将这些枚举值与人类可读的描述相关联。简单的方法是以与值相同的顺序创建字符串表。在生产代码中,您可能希望选择更易于维护的内容。请记住,令牌代码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;
}

最后,有点清理的词法分析器:

文件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全局(或重入扫描器的参数)来保存位置信息,为该信息添加令牌计数。

答案 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"); \
        } \
    }
%}