Flex with c++ 入门示例
凡是学过《编译原理》的大概对Flex都不陌生吧。
flex - fast lexical analyzer generator,这是GNU对其的定义,它的意思说Flex就是fast LEX,但是它是不是比AT&T的LEX好呢?我不知道。
首先,我们先开始我们的第一个事例吧,我们需要统计一个文档有多少行,有多少个字符。但是我又不想自己写函数,那么好,让Flex来帮我写吧
这是一个c++的例子,c的例子大家很容易在网上找到。C++稍微得麻烦点。因为即使是Flex的最新版本,它出的时候c++ standrad 也还在制定中,所以,由于namespace std的问题,编译的时候会遇到一些麻烦。
首先,用acmkdir新建一个目录,名为test,acmkdir具体怎么用,请参见我以前的文章《利用GNU 开发工具套件开发c++应用程序》(
http://www.blogcn.com/User5/snnn/blog/4919807.html)。然后在src目录下写入test.l
%{
int num_lines = 0, num_chars = 0;
%}
%%
\n ++num_lines; ++num_chars;
. ++num_chars;
%%
该文件一共分为三部分
前面用%{和%}括起来的是c/c++格式的变量声明,语句等,或者直接就是"#include "something"
中间两个%% ,%%是模式定义,使用的是正则表达式的方式对左面的模式进行匹配,如果匹配,就执行右面的语句。
最后在%%之后你还可以写你自己的c/c++函数,比如,你可以在这放一个main(){}
然后用flex生成
flex -+ test.l
注意,参数-+代表生成c++格式的源文件(lex.yy.cc),而不是c文件(lex.yy.c)
找了个死奴来帮我写代码,
去喝杯咖啡如何?
还是算了吧,在我刚起身的时候才发现,它生成一个31734字节的源文件只用了几ms,如果这个文件是要我自己来写的话。。。
要不要打开lex.yy.cc来看看呢?
1500多行,还是算了吧,相信它,它是不会出错的。
然后新建一个cpp文件,这是我的test.cpp文件
more test.cpp
/*! \file test.cpp
* \brief test.cpp
* \date 30 Nov 2004 22:05:31
* \author snnn119@hotmail.com
*/
/*
** Copyright (C) 2004 cyper sun <snnn119@hotmail.com>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
**
**
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <FlexLexer.h>
#include <fstream.h>
extern int num_lines,num_chars;
int main(int argc,char** argv){
if(argc == 1){
printf("usage:%s [file]",argv[0]);
return 1;
}
ifstream* pmyFile = new ifstream();
pmyFile->open(argv[1],ios::out);
if(pmyFile->fail()){
printf("error while open the file"
;return 1;
}
FlexLexer* lexer = new yyFlexLexer(pmyFile);
while(lexer->yylex()!=0);
printf("total lines:%d\ntotal chars:%d\n",num_lines,num_chars);
delete pmyFile;
delete lexer;
return 0;
}
注意这里的一点多态, yyFlexLexer是派生自 FlexLexer的派生类。 FlexLexer是一个抽象基类,它们都是在<FlexLexer.h>中定义的。
下面我简单的介绍下这两个类
------------------------------------------------------------------------------------------------------------------
Class FlexLexer:
这是一个抽象类
const char* YYText()
returns the text of the most recently matched token, the equiva-
lent of yytext.
返回最近一次匹配,同c格式下的yytext
int YYLeng()
returns the length of the most recently matched token, the
equivalent of yyleng.
返回最近一次匹配的长度,同c格式下的 yyleng
int lineno() const
returns the current input line number (see %option yylineno), or
1 if %option yylineno was not used.
返回最近一次匹配的行号,或者1,如果你在option中关闭了此项。 同c格式下的 yylineno
还有一些Member function如:
yy_create_buffer(),yy_flush_buffer(),yy_delete_buffer(),yyrestart()等等,具体用法请去读源代码。(sorry,there is no doc any more).
------------------------------------------------------------------------------------------------------------------
Class yyFlexLexer:
继承自 FlexLexer
yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0
这是它的构造函数,用一个iistream* arg_yyin 代替以前的yyin作输入,ostream* arg_yyout 作输出。也就是说它的输入和输出也可以是多种多样的,文件,cin等等。
如果你不特别指定,默认的输入和输出流依然是cin和cout
virtual int yylex()
对输入进行分析,在<FlexLexer.h>中定义,在lex.yy.cc中实现
virtual void LexerOutput( const char* buf, int size
将buf中size个字节写出到输出流。
其他的函数还是请参考<FlexLexer.h>
------------------------------------------------------------------------------------------------------------------
好了,然后修改src/Makefile.am,告诉它我们要编译什么
bin_PROGRAMS = test
test_SOURCES = test.cpp lex.yy.cc
INCLUDE =(all_include)
test_LDFLAGS = (all_libraries)
然后就是configure.ac了,检测目标机器上flex/lex是否存在
只需加入一行
AC_PROG_LEX
ok,编译
理论上来讲这样就行了,可是在我的机子上没有能通过,我的gcc 3.4坏了,现在用的是
gcc --version
gcc (GCC) 3.3.1 (cygming special)
它提示istream重定义
你可以在lex.yy.cc中找到那句对istream的前向声明,替换成#include <istream.h>
然后编译,运行,
./test test.l
total lines:25
total chars:145
注意,把程序命名为test是个坏习惯,因为在unix/linx系统上已经存在一个名为test的系统工具。
如果你需要查询某个特定的模式(比如邮件地址,标记)在某个文件中的出现次数,那么稍微改下test.l中的那两个正则表达式就行了