Flex lexer 如何防止Flex忽略以前的分析?
我最近开始使用Lex,作为解释我遇到的问题的一种简单方法,假设我正在尝试用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 [ \
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 */
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中使用。(请随意将评论转给你的教授。)但也许作业中还有比你提到的更多的内容。我想我缺少的是拒绝操作,实际上这就是作业中提到的全部内容,在添加拒绝并稍微修改代码后,问题就消失了,非常感谢