用flex生成C++的文件实例分析

本文介绍如何利用Flex工具生成不同前缀的词法分析器类,并在C++程序中同时使用多个词法分析器进行文件分析。文章详细展示了如何通过配置选项实现类名的定制,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

       flex是一个在unix/linux下经典的词法分析程序,能够灵活运用这个软件,会是你在linux下编程提供方便。我前篇blog简单的谈了一下用flex生成一个c++分析程序,还记得我们生成的默认的分析类是xxFlexLexer,可是如果我们在某个程序中需要两个这样的不同的类该怎么办呢(这两个类的功能也不同)!!,总不能是两个类都用同样的xxFlexLexer这个名字吧!!,我花了半天的功夫总算弄得半个明白,下面就将我的成果和大家分享一下,希望对大家有所帮助。

 

下面是count.l的词法分析描述文件,这个文件中描述了一个用于计数字符个数和文件行数的规则:

 
%{   

    #include "data.h"
    extern data newData;
   
%}

%option nounput
%option prefix="xx"
%option outfile="hostParser.cc"


%%

/n      newData.incNumLines(); newData.incNumChars();

.       newData.incNumChars();

%%


int yywrap()
{
    return 1;
}
注意%prefix="xx"标识了我们要生成的类的前缀是xx。而yywrap这个函数是必须有的,这个在这里就不解释了,只要

记得每个.l文件都要有他就行了。

 

下面是infor文件,这个文件能够区分你输入的是数字还是字符,他也是一个词法描述文件

%{
#include<iostream>
using std::cout;
int mylineno = 0;

%}


%option nounput
%option prefix="zz"
%option outfile="info.cc"

string  /"[^/n"]+/"

ws      [ /t]+

alpha   [A-Za-z]
dig     [0-9]
name    ({alpha}|{dig}|/$)({alpha}|{dig}|[_./-/$])*
num1    [-+]?{dig}+/.?([eE][-+]?{dig}+)?
num2    [-+]?{dig}*/.{dig}+([eE][-+]?{dig}+)?
number  {num1}|{num2}

%%

{ws}    /* skip blanks and tabs */

"/*"    {
        int c;

        while((c = yyinput()) != 0)
            {
            if(c == '/n')
                ++mylineno;

            else if(c == '*')
                {
                if((c = yyinput()) == '/')
                    break;
                else
                    unput(c);
                }
            }
        }

{number}  cout << "number " << YYText() << '/n';

/n        mylineno++;

{name}    cout << "name " << YYText() << '/n';

{string}  cout << "string " << YYText() << '/n';

%%

int yywrap()
{
    return 1;
}

注意到%option prefix="zz",他告诉我们,我们要生成的类前缀是zz

 

下面是一个简单的 c++文件,在这里并不是主角,相信大家都能看懂。

data.h文件

 

#ifndef __DATA_H
#define __DATA_H   

class data{
protected:
    int num_lines;
    int num_chars;
public:
   
    void incNumLines();
    void incNumChars();
   
    int getNumLines();
    int getNumChars();

    data();


};
#endif

 

data.cpp文件

#include "data.h"


data::data()
{
    num_lines = 0;
    num_chars = 0;
}

void data::incNumLines()
{
    num_lines++;
}
void data::incNumChars()
{
    num_chars++;
}

int data::getNumLines()
{
    return num_lines;
}
int data::getNumChars()
{
    return num_chars;
}

 

information.h文件

#ifndef __INFORMATION
#define __INFORMATION

class information
{
public:
    void getInfor();

};
#endif

 

information.cpp文件

#include "information.h"
#undef yyFlexLexer
#define yyFlexLexer zzFlexLexer
#include <FlexLexer.h>



void information::getInfor()
{
    FlexLexer* lexer = new zzFlexLexer;
        while(lexer->yylex() != 0)
            ;
}

 

最后给出main.cpp文件:

#include <fstream.h>
#include <string.h>
#include <stream.h>
#include "data.h"
#include "information.h"

#undef yyFlexLexer
#define yyFlexLexer xxFlexLexer
#include <FlexLexer.h>




data newData;
int main( int /* argc */, char* argv[] )
    {
     ifstream* pmyFile = new ifstream();
     pmyFile->open(argv[1],ios::out);
   
      FlexLexer* lexer = new  xxFlexLexer(pmyFile);
 
    while(lexer->yylex()!=0);
     printf("total lines:%d/ntotal chars:%d/n",newData.getNumLines(), newData.getNumChars());
    information infor ;
    infor.getInfor();
  delete pmyFile;
    delete lexer;
 return 0;
    }

我们需要说明的是,在main.cpp和information.cpp文件中分别有如下预处理:

information.cpp

#undef yyFlexLexer
#define yyFlexLexer zzFlexLexer
#include <FlexLexer.h>

 

main.cpp

#undef yyFlexLexer
#define yyFlexLexer xxFlexLexer
#include <FlexLexer.h>

 

这使得两个文件中使用了不同的词法分析类:

information.cpp

    FlexLexer* lexer = new zzFlexLexer;
    while(lexer->yylex() != 0;
main.cpp

    FlexLexer* lexer = new  xxFlexLexer(pmyFile);
    while(lexer->yylex()!=0);

这样程序就会调用不同的分析方法来进行分析了。

这里的while循环是必须的,这个体空的while循环完成了对文件的一次扫描。

 

有人会问,为什么要定义一个information.h呢!!!,能不能直接在main函数中使用两个不同的分析方法呢?

答案是很遗憾,目前还不支持这重方法。

还有一个问题就是外部变量无法直接传入到词法分析类中,词法分析类必须通过extern来引用外部变量,这个在前面的例子中我们可以看到。

最后一个问题是语法分析程序(bison),对c++并没有很好的支持,所以我们可以通过flex直接完成语法分析部分

也是可以的,相关例子可一在网上找到,这里就不累述。

最后给一个简单的makefile以供参考:

main: main.o data.o information.o
    flex -+ -Pxx count.l
    flex -+ -Pyy info.l
    g++ main.cpp data.cpp information.cpp hostParser.cc info.cc -o main

clear:
    rm -rf *~ *.cc *.o main

如果有什么意见和看法,可以给我留言,大家一起探讨学习。

本文是由作者个人所写,如有转载请标明出处。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值