分类:
2012-10-28 11:10:26
原文地址:Redy词法分析--输入缓冲区的设计与实现 作者:NosicLin
代码下载: git clone git://git.code.sf.net/p/redy/code redy-code这一章的内容有:
输入缓冲区的设计与实现
- struct lex_file
- {
- FILE* l_file;
- char* l_buf;
- int l_buf_cap;
- int l_buf_size;
- int l_begin;
- int l_mark;
- int l_read_pos;
- };
输入缓冲区的创建有两种方法,一种从指定的文件名中创建输入缓冲区,别一是从已经打开的文件中创建缓冲区,在他们内部都调用lf_init()来对输入缓冲区进行初始化输入缓冲区的创建代码:
- void lf_init(struct lex_file* lf,FILE* file)
- {
- lf->l_file=file;
- lf->l_buf=(char*)malloc(LEX_FILE_DEFAULT_SIZE);
- lf->l_buf_cap=LEX_FILE_DEFAULT_SIZE;
- lf->l_buf_size=0;
- lf->l_begin=0;
- lf->l_mark=0;
- lf->l_read_pos=0;
- };
- struct lex_file* lf_create(char* file_name)
- {
- FILE* file=fopen(file_name,"r");
- if(file==NULL)
- {
- return NULL;
- }
- struct lex_file* lf=(struct lex_file*)malloc(sizeof(*lf));
- lf_init(lf,file);
- return lf;
- }
- struct lex_file* lf_stream_create(FILE* file)
- {
- if(file==NULL)
- {
- BUG("NULL Pointer");
- return NULL;
- }
- struct lex_file* lf=(struct lex_file*)malloc(sizeof(*lf));
- lf_init(lf,file);
- return lf;
- };
输入缓冲区的销毁代码:
- void lf_destory(struct lex_file* lf)
- {
- free(lf->l_buf);
- fclose(lf->l_file);
- free(lf);
- }
b)从文件中读取数据到缓冲区,读取数据到缓冲区的过程分:
- 判断缓冲区中是否存数据,如果没有直接从文件中读取数据
- 计算缓冲区的可用空间,看是否能在读取LEX_FILE_DEFALUT_SIZE/2大小的数据,如果不能,则把缓冲区扩大成为原来的2倍,这种情况可能发生在识别一个长字符串词文时。
- 移除已使用过作费的的数据,为新读入的数据腾出空间,把有效的数据移到缓冲区的开头。
- 读取新数据到缓冲区
代码为:
- int lf_load_data(struct lex_file* lf)
- {
- int readbyte;
- if(lf->l_buf_size==0)
- {
- readbyte=fread(lf->l_buf,sizeof(char),LEX_FILE_DEFAULT_SIZE,lf->l_file);
- lf->l_buf_size=readbyte;
- return readbyte;
- }
- int begin=lf->l_begin;
- int mark=lf->l_mark;
- int read_pos=lf->l_read_pos;
- int buf_cap=lf->l_buf_cap;
- int buf_used=read_pos-begin;
- int buf_free=buf_cap-buf_used;
- if(buf_free<LEX_FILE_DEFAULT_SIZE/2)
- {
- char* new_buf=(char*)malloc(lf->l_buf_cap*2);
- memcpy(new_buf,lf->l_buf+begin,buf_used);
- free(lf->l_buf);
- lf->l_buf=new_buf;
- lf->l_buf_cap=lf->l_buf_cap*2;
- }
- else
- {
- int i;
- char* buf=lf->l_buf;
- for(i=0;i<buf_used;i++)
- {
- buf[i]=buf[i+begin];
- }
- }
- lf->l_begin=0;
- lf->l_mark=mark-begin;
- lf->l_read_pos=read_pos-begin;
- readbyte=fread(lf->l_buf+buf_used,sizeof(char),lf->l_buf_cap-buf_used,lf->l_file);
- lf->l_buf_size=buf_used+readbyte;
- return readbyte;
- }
c)从输入缓冲区中读取一个字符,先判断读取位置是否以到达缓冲区数据尾端,如果是则从文件中加载数据代码为:
- static inline char lf_next_char(struct lex_file* lf)
- {
- if(lf->l_read_pos>=lf->l_buf_size)
- {
- if(lf_load_data(lf)==0)
- {
- return EOF;
- }
- }
- return lf->l_buf[lf->l_read_pos++];
- }
d)对当前读取位置进行标记,以便以后可以重新回到该位置进行读写代码为:
- static inline void lf_mark(struct lex_file* lf)
- {
- lf->l_mark=lf->l_read_pos;
- }
e)回到标记位置代码为:
- static inline void lf_back_to_mark(struct lex_file* lf)
- {
- lf->l_read_pos=lf->l_mark;
- }
- static inline void lf_reset_to_mark(struct lex_file* lf)
- {
- lf->l_begin=lf->l_mark;
- lf->l_read_pos=lf->l_mark;
- }
返回文档首页到现在,我们已经完成一个高效率的输入缓冲区。