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

问题描述 投票:1回答:1

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

 QQQZ ,JQR

结果是

 Bigram QQ
 Bigram QZ
 Bigram JQ
 Letter R
 Done

这是我的lex代码

 %{ 

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

我的问题是如何分开实现这两个分析,知道我的实际问题并不像这个例子那么简单

flex-lexer lex lexical-analysis
1个回答
3
投票

词法分析器将源文本划分为单独的标记。如果您的问题看起来像那样,那么(f)lex是一个合适的工具。如果你的问题看起来不像那样,那么(f)lex可能不是正确的工具。

对文本进行两次同时分析并不是(f)lex的用例。一种可能性是使用两个独立的折返词法分析器,安排给它们提供相同的输入。然而,对于一个可以在几行C中轻松解决的问题,这将是很多工作。

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

如果你的问题确实与来自同一起始位置的两个(或更多)不同的词汇相匹配,你可以使用两种策略中的一种,两者都非常难看(恕我直言):

  1. 我假设存在处理函数: void handle_letter(char ch); void handle_bigram(char* s); /* Expects NUL-terminated string */ void handle_trigram(char* s); /* Expects NUL-terminated string */
  2. 由于历史原因,lex实现了REJECT动作,这会导致当前匹配被丢弃。我们的想法是让您处理匹配,然后拒绝它以处理更短(或替代)的匹配。使用flex时,强烈建议不要使用REJECT,因为它的效率非常低,并且还会阻止词法分析器调整输入缓冲区的大小,这会随意限制可识别令牌的长度。但是,在这个特定的用例中,它非常简单: [[:alpha:]][[:alpha:]][[:alpha:]] handle_trigram(yytext); REJECT; [[:alpha:]][[:alpha:]] handle_bigram(yytext); REJECT; [[:alpha:]] handle_letter(*yytext); 如果你想尝试这个解决方案,我建议使用flex的调试工具(flex -d ...)来查看发生了什么。 见debugging optionsREJECT documentation
  3. 我实际建议的解决方案,虽然代码有点笨拙,但是使用yyless()来重新处理部分识别的令牌。这比REJECT更有效率; yyless()只更改一个指针,因此它对速度没有影响。如果没有REJECT,我们必须知道所需的所有lexeme处理程序,但这并不是很困难。复杂性是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); yyless() documentation
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.