首页 > 代码库 > 编译器DIY——读文件

编译器DIY——读文件

编译器的前端词法分析:将源文件解析成一个个的单词流,为语法分析做准备。

在词法分析阶段,我们要做的就是将词分出来,并且确定单词的类型,一般的程序设计语言的单词符号可以份为以下5种:

1.关键字,如int,long等

2.标识符,用来表示各种名字,如常量名,变量名等

3.常数,各种类型的常数,如12,1.2等

4.运算符:如+,-,*,/等

5.界符,如“,”“;”等

那么在实际的过程中应该如何来区分这5中类型,在后面的文章中我将具体讲到。

词法分析第一阶段,很明显,需要从源文件中读取数据。考虑到现在的硬件内存都达到了2G及以上的标准,那么就将全部源文件读到内存中,并设置指针指向头位置,那么在随后的分词操作中,将直接操作指针即可。在其他的编译器中,很多类型都是从文件中按行读取然后对该行中的数据进行解析,这样做的好处就是空间的大大节省,特别是当内存紧凑的时候。而我之所以全部读取,不仅仅是因为硬件的原因,还有一个原因是在随后的分词中,我会相对简单一些。


我们先构造一个结构用来存储对源文件有关的操作:

struct File {
    void *file;// 指向文件的指针
	char *fileName;//文件名
	unsigned char *cursor;//光标的位置
	unsigned char *first;//内存区的首地址
	unsigned long size;//文件的大小
};


接着用一个函数来实现读取源文件的操作:

int readSourceFile(char *fileName) {
	source.file = fopen(fileName, "r");
	if (source.file == NULL) {
		Error("Can not open file.\n");
		return 0;
	}
	source.fileName = fileName;
	fseek(source.file, 0, SEEK_END);
	source.size = ftell(source.file);
	source.first = malloc(source.size + 1);
	if (source.first == NULL) {
		Error("The file is too big");
		fclose(source.file);
		return 0;
	}
	fseek(source.file, 0, SEEK_SET);
	source.size = fread(source.first, 1, source.size, source.file);
	fclose(source.file);
	source.first[source.size] = END_OF_FILE;
	source.cursor = source.first;
    return 1;
}

用fseek重定位文件的指针,ftell来取得指针对于文件首部的偏移量,从而得出文件的大小,接着开辟等量的空间,最后对文件结构体进行赋值


在编译器中因为要对错误进行处理,所以就将所有的出错函数封装起来,以便随时调用。

出错函数:

void Error(const char *format, ...)
{
	va_list ap;
	fprintf(stderr, "error:");
	va_start(ap, format);
	vfprintf(stderr, format, ap);
	fprintf(stderr, "\n");
	va_end(ap);
}

void Warning(const char *format, ...)
{
	va_list ap;
	fprintf(stderr, "warning:");
	va_start(ap, format);
	vfprintf(stderr, format, ap);
	fprintf(stderr, "\n");
	va_end(ap);

	return;
}

最后我们来进行测试:

测试函数:

/*
 * debug put all content from source file
 * */
void putSrc(){
    unsigned char *ch=source.first;
    while(*ch != END_OF_FILE){
    	printf("%c", *ch++);
    }
}


主函数:

int main() {
     readSourceFile("test.txt");
     putSrc();

}

到这里我们完成了词法分析的第一步,在下篇文章中就是对源文件中的数据进行解析。