Flex lexer 如何防止Flex忽略以前的分析?

Flex lexer 如何防止Flex忽略以前的分析?,flex-lexer,lex,lexical-analysis,Flex Lexer,Lex,Lexical Analysis,我最近开始使用Lex,作为解释我遇到的问题的一种简单方法,假设我正在尝试用Flex实现一个词汇分析器,它可以打印给定文本中的所有字母和所有双字符,这看起来非常简单,但是一旦我实现了它,我已经意识到,它首先显示的是大字组,只有当它们是单字时才会显示字母,例如:下面的文本 QQQZ ,JQR 结果是 Bigram QQ Bigram QZ Bigram JQ Letter R Done 这是我的莱克斯密码 %{ %} letter[A-Za-z] Separ [ \

我最近开始使用Lex,作为解释我遇到的问题的一种简单方法,假设我正在尝试用Flex实现一个词汇分析器,它可以打印给定文本中的所有字母和所有双字符,这看起来非常简单,但是一旦我实现了它,我已经意识到,它首先显示的是大字组,只有当它们是单字时才会显示字母,例如:下面的文本

 QQQZ ,JQR
结果是

 Bigram QQ
 Bigram QZ
 Bigram JQ
 Letter R
 Done
这是我的莱克斯密码

 %{ 

  %}
  letter[A-Za-z]
  Separ [ \t\n]
   %%
  {letter} {
  printf(" Letter %c\n",yytext[0]);
   }

  {letter}{2} {
  printf(" Bigram %s\n",yytext);
  }
  %%
  main()
  { yylex();
  printf("Done");
   }
我的问题是,如果知道我的实际问题并不像这个例子那么简单,那么如何分别实现这两种分析呢。如果您的问题是这样的,那么(f)lex是一个合适的工具。如果您的问题不是这样,那么(f)lex可能不是正确的工具

同时对文本进行两次分析并不是(f)lex真正的用例。一种可能是使用两个独立的可重入词法分析器,安排为它们提供相同的输入。然而,对于一个可以用几行C语言轻松解决的问题来说,这将是一个很大的工作

因为你说你的问题不同于你问题中的简单问题,所以我没有费心编写简单的C代码或更复杂的代码来生成并运行两个独立的词法分析器,因为不可能知道这些解决方案是否相关

如果你的问题真的是从同一起始位置匹配两个(或多个)不同的词素,你可以使用两种策略中的一种,这两种策略都非常难看(IMHO):

  • 我假设存在处理函数:

    void handle_letter(char ch);
    void handle_bigram(char* s);  /* Expects NUL-terminated string */
    void handle_trigram(char* s); /* Expects NUL-terminated string */
    
  • 出于历史原因,lex实现了
    REJECT
    操作,这将导致丢弃当前匹配。这个想法是让你处理一个匹配,然后拒绝它,以便处理一个较短的(或备用)匹配。使用flex时,非常不鼓励使用
    REJECT
    ,因为这极为低效,并且还阻止lexer调整输入缓冲区的大小,从而任意限制可识别令牌的长度。然而,在这个特定的用例中,它非常简单:

    [[:alpha:]][[:alpha:]][[:alpha:]]   handle_trigram(yytext); REJECT;
    [[:alpha:]][[:alpha:]]              handle_bigram(yytext); REJECT;
    [[:alpha:]]                         handle_letter(*yytext);
    
    如果您想尝试这个解决方案,我建议您使用flex的调试工具(
    flex-d…
    )来查看发生了什么

    见和

  • 我实际上建议的解决方案是使用
    yyless()
    重新处理已识别令牌的一部分,尽管代码有点笨重。这比拒绝要有效得多
    yyless()
    只更改一个指针,因此它对速度没有影响。如果没有拒绝,我们必须知道所有需要的词素处理程序,但这并不困难。一个复杂的问题是
    handle_bigram
    的接口,它需要以NUL结尾的字符串。如果您的处理程序没有强加此要求,代码将更简单

    [[:alpha:]][[:alpha:]][[:alpha:]]   { handle_trigram(yytext);
                                          char tmp = yytext[2];
                                          yytext[2] = 0;
                                          handle_bigram(yytext);
                                          yytext[2] = tmp;
                                          handle_letter(yytext[0]);
                                          yyless(1);
                                        }
    [[:alpha:]][[:alpha:]]              { handle_bigram(yytext);
                                          handle_letter(yytext[0]);
                                          yyless(1);
                                        }
    [[:alpha:]]                         handle_letter(*yytext);
    


  • 我的实际问题是计算给定文本中字母、双字符和三叉字符的频率,我需要使用(f)lex,对于字母的频率,我使用了链表的概念,效果很好,但对于双字符,一切都消失了,我希望你收到我的信point@YaSsou:您是否应该将自己限制在与特定模式(例如“仅字母”)匹配的NGRAM中?(虽然对我来说,(f)lex还是不太合适。)我不明白你的问题,但我的任务要求使用flex来计算字符的频率(我想不仅仅是字母),bigrams和trigrams/@YaSsou:好的。我写了一些解决方案,假设只有字母字符的字母表才重要。你必须相应地调整它,这是合理的,因为这是你的任务,而不是我的。如果作业的目的是学习一些关于flex的知识,那么在我看来它并不是那么有用,因为这些技巧很少在实际的Lexer中使用。(请随意将评论转给你的教授。)但也许作业中还有比你提到的更多的内容。我想我缺少的是拒绝操作,实际上这就是作业中提到的全部内容,在添加拒绝并稍微修改代码后,问题就消失了,非常感谢