问题描述
我正在运行以下lex程序,该程序可以很好地识别关于猫的句子:
var5
我得到以下输出:
main
但是,当我尝试向程序中添加OR语句(针对ARTICLE)时,不再识别出cat语句:
%{
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
extern "C" int yylex();
%}
SP [ ]+
ARTICLE "le" /* Line I am trying to change */
COMMUN "chat"
VERBE "est"
NOIR "noir"
PHRASE {ARTICLE}{SP}{COMMUN}{SP}{VERBE}{SP}{NOIR}
%%
^{PHRASE}\n { cout << "Une phrase : " << yytext << '\n'; }
\n { cout << '\n'; }
^.*\n { cout << "Ligne inconnue : " << yytext << '\n'; }
%%
int main(int argc,char *argv[])
{
++argv,--argc;
if(argc > 0)
yyin = fopen(argv[0],"r");
else
yyin = stdin;
yylex();
} /* main() */
这将为我提供以下输出:
Ligne inconnue : le professeur est Jean
Ligne inconnue : le professeur a un ordinateur
Ligne inconnue : Jean aime Linux
**Une phrase : le chat est noir**
Ligne inconnue : les etudiants ont des ordinateurs
%{
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
extern "C" int yylex();
%}
SP [ ]+
ARTICLE "le"|"la" /* Line I am trying to change */
COMMUN "chat"
VERBE "est"
NOIR "noir"
PHRASE {ARTICLE}{SP}{COMMUN}{SP}{VERBE}{SP}{NOIR}
%%
^{PHRASE}\n { cout << "Une phrase : " << yytext << '\n'; }
\n { cout << '\n'; }
^.*\n { cout << "Ligne inconnue : " << yytext << '\n'; }
%%
int main(int argc,"r");
else
yyin = stdin;
yylex();
}
谁能告诉我为什么这行不通?我尝试了可以在网上找到的OR语句的所有变体,但仍然没有任何效果。
谢谢!
解决方法
实现了flex -l
标志,以便可以继续处理真正无法使用的lex规范。对于任何新编写的扫描仪,您实际上都不需要该标志。这个特殊问题是常见原因。
问题出在宏扩展的处理上:flex做常识性事情,避免了很多常见错误; lex(和flex -l
)使您更容易使用宏定义拍摄脚步。
以防万一,在lex所谓的“定义”中,实际上是一个宏。就像C预处理器宏一样,lex宏也会引入许多潜在的误解。
我想几乎所有使用过预处理器的C程序员都偶然发现了这个陷阱:
#define SUM(a,b) a+b // DON'T DO THIS,EVER
尽管您可以在某些情况下成功使用此宏,但最终您会发现
int c = SUM(a,b) * 2;
计算a+b*2
而不是预期的(a+b)*2
。那是因为宏替换只是符号替换;如果宏中没有括号,则不会生成括号。
这也是lex的工作方式,也是Posix标准所说的应该工作的方式。但是很多年前,flex的作者意识到,没有人期望像下面这样的定义能够像他们一样工作:
ARTICLE "le"|"la"
%%
{ARTICLE}" chat" { /* Matches either "le" or "la chat" */ }
因此,flex(通常)会自动插入所需的括号,就像您已将ARTICLE
正确定义为:
ARTICLE ("le"|"la")
但是,这与原始lex不兼容,并且可能会破坏依赖于原始烦人的文字语义的旧lex程序。
因此flex提供了-l
(“ Lex兼容性”)选项,该选项可用于处理这些旧的lex程序。但是,正如我所说,不应将其用于任何新的lex程序。
以防万一上述内容不足以令人信服,这并不是-l
标志保留的原始lex唯一的错误选择。另一个是计数重复运算符{m,n}
的奇异运算符优先级。在Flex中,
ab* ab+ ab? ab{0,3}
分别为:
- “后跟零个或多个
a
的{{1}}” - “一个
b
后跟一个或多个a
” - “
b
后跟可选的a
” - “从
b
的零个重复到三个重复”
Flex通过使方括号重复的运算符优先级与任何其他重复运算符的运算符优先级相同来解决此不一致问题,这无疑是每个人都期望的。同样,ab
标志恢复为原始lex规范。
最后,-l
选项使默认的-l
声明是数组而不是指针。尽管这样做可以使一些事情变得容易,但总体上带来了一些重要的缺点,包括:
- 慢很多。
- 它防止扫描程序调整其缓冲区大小以应对长令牌
最重要的是:不要使用flex yytext
选项(也不是,在我们讨论此主题时,使用野牛-l
选项),除非您需要它来编译旧代码。>