flex+bison解析配置文件

来源:互联网 发布:嵌入式linux入门教材 编辑:程序博客网 时间:2024/06/06 05:19

1   引言

       由于之前读linux和ubuntu的时候,出现scripts/kconfig/conf程序用于配置整个工程,出现一个yyparse函数,数千行,后来的之是flex+bison生成的。接下来就是做一个程序,简单了解写flex+bison。程序主要是为了读取一个my_config文件。my_config如下:

config"FIRST"

  type 0

  value 999

  help "first help"

CONFIG"SECOND"

  type 0

  value 2

  help "second help"

config"THIRD"

  type 0

  value "I am the Third!"

  depend "FIRST" "SECOND"

  help "third help"

    为了简便,这里仅仅设置两者类型,整形和字符型,对于所有字符型数均采用加””方式识别。

    笔者指向了解一下flex+bison,仅列出实验过程。理论主要来源入如下三面文章:

(1)《flex和bison的用于加载和解析配置文件(参考freeDiameter用法)

http://blog.csdn.net/ncepubdtb/article/details/42707131

(2)《写编译器:学习GNU Flex,写一个词法分析器》

 

http://xiaoxia.org/2011/10/24/writing-a-compiler-learning-gnu-flex-write-a-lexical-analyzer/

 (3)《 语法分析器 BISON》

 http://blog.sina.com.cn/s/blog_aed82f6f01019fp6.html

2   代码

源码包括conf.l,conf.y,conf.h,main.c,Makfile还有一个要处理的配置文件my_config。

2.1 Makefile

.PHONY = all

all:

    flex-o lex.yy.cpp conf.l

    bison-d -o conf.tab.cpp conf.y

    g++-o main main.cpp lex.yy.cpp conf.tab.cpp -I./

clean:

    rm-rf lex.yy.cpp main conf.tab.cpp conf.tab.hpp

2.2 main.c

#include "config.h"

#include "stdio.h"

#include <string.h>

using std::cout;

using std::endl;

struct symbol * g_conf_list;

extern int yyparse(char * file);

void dump_conf(struct symbol * conf)

{

    cout<<"config:"<<conf->name<<endl;

    cout<<"type:"<<conf->type<<endl;

    cout<<"value:"<<conf->type<<endl;

    cout<<"dep:";

    for(inti=0;i<conf->dep_num;i++)

        cout<<conf->dep[i]<<"";

    cout<<"\n";

    cout<<"help:"<<conf->help<<endl;

    cout<<"\n";

}

int main()

{

    char* file_name = "my_config";

    externFILE * yyin; int ret;

    yyin= fopen(file_name, "r");

    if(yyin == NULL)

    {

        cout<<"my_configdoes not exist!"<<endl;

    }

    cout<<"parsemy_config..."<<endl;

    yyparse(file_name);

    cout<<"endparse my_config"<<endl;

    cout<<"\n";

    structsymbol * cur_conf_list = g_conf_list;

    if(cur_conf_list== NULL)

        cout<<"isNULL"<<endl;

    while(NULL!= cur_conf_list)

    {

        dump_conf(cur_conf_list);

        cur_conf_list = cur_conf_list->next;

    }  

 

    return1;

}

2.3 config.h

#ifndef CONFIG_H

#define CONFIG_H

#include <iostream>

#include <string>

 

struct symbol_value {

    std::stringstr;

    int number;

};

#define S_DEF_COUNT 10

struct symbol {

    structsymbol * next;

    std::stringname;

    inttype;           //0表示int,1表示string

    structsymbol_value value;

    intdep_num;

    std::stringdep[S_DEF_COUNT];

    std::stringhelp;

};

#endif

2.4 conf.l

%{

#include "conf.tab.hpp"

#include <iostream>

using std::cout;

using std::endl;

%}

 

%option noyywrap

digit   [0-9]

number  {digit}+

 

%%

(?i:config) {

                /*读到config表示一个新的symbol开始, i表示不区分大小写  */

                returnCONFIG_START;

            }

 

(?i:type)       {

                /*  读到type表示即将设置symbole类型symbol_typer,并且后面的值便是设置值   */

                returnCONFIG_TYPE;

            }

 

(?i:value)      {

                /*  读到value表示即将设置symbole类型symbol_value的str或number,并且后面的值便是设置值*/

                returnCONFIG_VALUE;

            }

 

(?i:depend) {

                /*  读到depend on, 表示设置依赖列表,并且后面的值便是依赖列表(是字符串型)*/

                returnCONFIG_DEPEND;

            }

 

(?i:help)       {

                /*  读到help, 表示设置帮助,并且后面的值便是以来(是字符串型)*/

                returnCONFIG_HELP;

            }

 

 

\"[^\"]+\"  {

                /*  字符串,不支持""  */

                //yytext对应读取的这个内容的指针,yyleng为其长度。yylval对应.y文件的union

                //这里有一个问题,不知道在那里free的,暂时不去深究。

                yylval.string= (char * )malloc(512);

                memset(yylval.string,0,512);

                memcpy(yylval.string,yytext,yyleng);

                returnSET_STRING;

            }

           

[0-9]+  {

             /* 数字,仅支持正整数 */

            //yytext对应读取的这个内容的指针,yylval对应.y文件的union

            intret = sscanf(yytext, "%i", &(yylval.integer));

            if (ret != 1)

                {returnLEX_ERROR;}

            returnSET_UINT;

        }

 

[\t]    {/*其中'\t'和'\n'以及空格都是合法的*/}

[\n]    {/*其中'\t'和'\n'以及空格都是合法的*/}

[ ]     {/*其中'\t'和'\n'以及空格都是合法的*/}

 

.   {

            printf("illegalword!\n");

            returnLEX_ERROR;

    }

%%

2.5 conf.y

%parse-param {char * conffile}

 

%{

 

#include "config.h"

#include <string>

#include <string.h>

extern struct symbol * g_conf_list;

struct symbol * current_conf_list;

 

int config_enable = 0;      //只有分配内存之后才能配置

/*  flex的解析函数  */

int yylex (void);

/* bison的默认解析函数, Forwarddeclaration */

int yyparse(char * file);

using std::cout;

using std::endl;

 

void yyerror(char * conffile, charconst *s)

{

}

 

void init_symbol(struct symbol * ptr)

{

    ptr->next= NULL;

    ptr->name= "";

    ptr->name.clear();

    ptr->type= 0;

    memset(&(ptr->value),0,sizeof(structsymbol_value));

    ptr->dep_num= 0;

    for(inti=0;i<S_DEF_COUNT;i++)

    {

        ptr->name= "";

        ptr->dep[i].clear();

    }

    ptr->help= "";

    ptr->help.clear();

}

 

%}

//对应于yylval这个变量,联合体应该包括所有可能的类型

%union {

   int             integer;    /* 保存整型数 */

   char*           string;     /* 保存字符串 */

}

/* 错误标识 */

%token LEX_ERROR

/*  配置标志    */

%token CONFIG_START

%token CONFIG_TYPE

%token CONFIG_VALUE

%token CONFIG_DEPEND

%token CONFIG_HELP

 

/*  配置值  */

%token <string> SET_STRING

%token <integer> SET_UINT

 

%%

/*语法定义*/

 

 

grammar:        /* empty grammar is OK */

            |grammar after_read_config

            |grammar after_read_type

            |grammar after_read_value_uint

            |grammar after_read_value_string

            |grammar after_read_help

            |grammar after_read_depend

            |grammar after_read_depend_append

            ;

 

//读取config之后

after_read_config: CONFIG_STARTSET_STRING

    {

        if(current_conf_list== NULL)

        {

            //current_conf_list= (struct symbol *)malloc(sizeof(struct symbol));

            g_conf_list= new struct symbol;

            current_conf_list= g_conf_list;

        }

        else

        {

            //current_conf_list->next= (struct symbol *)malloc(sizeof(struct symbol));

            current_conf_list->next= new struct symbol;

            current_conf_list= current_conf_list->next;

        }

        //memset(current_conf_list,0,sizeof(structsymbol));

        //因为有结构题,所以不能使用memset

        init_symbol(current_conf_list);

 

        current_conf_list->name= $2;

        config_enable= 1; 

    }

    ;

   

//读type行

after_read_type: CONFIG_TYPE SET_UINT

    {  

        if((current_conf_list!= NULL)&&(config_enable==1))

        {

            current_conf_list->type= $2;

        }

    }

    ;

 

//读value行,确保value在type下面设置才能保证有效

after_read_value_uint: CONFIG_VALUESET_UINT

    {  

        if((current_conf_list!= NULL)&&(current_conf_list->type ==0)&&(config_enable==1))

        {

            current_conf_list->value.number= $2;

        }

    }

    ;

 

after_read_value_string: CONFIG_VALUESET_STRING

    {  

        if((current_conf_list!= NULL)&&(current_conf_list->type ==1)&&(config_enable==1))

        {

            current_conf_list->value.str= $2;

        }

    }

    ;

 

//读help行

after_read_help: CONFIG_HELP SET_STRING

    {  

        if((current_conf_list!= NULL)&&(config_enable==1))

        {

            current_conf_list->help= $2;

        }

    }

    ;

 

//读depend行,读其中第一个依赖

after_read_depend:  CONFIG_DEPEND SET_STRING

    {

        if((current_conf_list!= NULL)&&(config_enable==1))

        {

            current_conf_list->dep[0]= $2;

            current_conf_list->dep_num= 1;

        }

    }

 

after_read_depend_append:   after_read_depend SET_STRING

    {

        if((current_conf_list!=NULL)&&(config_enable==1)&&(current_conf_list->dep_num<S_DEF_COUNT))

        {

            current_conf_list->dep[current_conf_list->dep_num++]= $2;

        }

    }

3   实验

    程序主要是读取my_config文件到类型为symbol的链表中,并打印出来。

(1) make

(2)./main

会出现如下结果:

 

 

 

 

 

0 0
原创粉丝点击