辣鸡用C语言实现解释器(二)
文件读入方式
使用fgets函数。
函数功能为从指定的流中读取<span 数据,每次读取一行。其原型为:<span str 所指向的字符串内。当读取<span
值得一提的是,如果是读到换行符停止后,str所指向字符串倒数第二个字符为‘\n’,最后一个字符为‘\0'。
read_file函数中实现文件的逐行读入以及简单的“分拣”:
int read_file(char *filename)
{
FILE *fp;
fp=fopen(filename,"r");
if(fp==NULL)
{
// printf("不能读取文件\n");
return NO;
}
//创建缓冲区buffer
char *buffer=NULL;
buffer=(char*)malloc(sizeof(char)*100);
if(!buffer)
{
// printf("缓冲区创建失败");
return NO;
}
// else printf("缓冲区预备\n") ;
//对文件进行操作
// printf("开始读取…\n");
while(!feof(fp))
{
if(!fgets(buffer,100,fp)) break;
operate_buffer(buffer);
if(buffer[0]=='/'&&buffer[1]=='/')
goto here;
if(buffer[0]=='\n')
break;
// int
if(buffer[0]=='i'&&buffer[1]=='n'&&buffer[2]=='t')
{
read_int(buffer);
}
// float
else if(buffer[0]=='f'&&buffer[1]=='l'&&buffer[2]=='o'&&buffer[3]=='a'&&buffer[4]=='t')
{
read_float(buffer);
}
// string
else if(buffer[0]=='s'&&buffer[1]=='t'&&buffer[2]=='r'&&buffer[3]=='i'&&buffer[4]=='n'&&buffer[5]=='g')
{
read_string(buffer);
}
// 条件语句
else if(buffer[0]=='i'&&buffer[1]=='f'&&buffer[2]==' '&&strchr(buffer,'{'))
{
if_func(buffer,fp);
}
// 循环语句
else if(buffer[0]=='f'&&buffer[1]=='o'&&buffer[2]=='r')
{
change_buffer(buffer,fp);
}
// 函数 read
else if(strchr(buffer,'r')&&strchr(buffer,'e')&&strchr(buffer,'a')&&strchr(buffer,'d')&&strchr(buffer,'(')&&(!strchr(buffer,',')))
{
func_read(buffer);
}
else if(strstr(buffer,"else")&&flag_for==0)
{
}
else if(strstr(buffer,"else")&&flag_for==1)
{
while(1)
{
fgets(buffer,100,fp);
if(strchr(buffer,'}')) break;
}
}
// 函数print
else if(strchr(buffer,'p')&&strchr(buffer,'r')&&strchr(buffer,'i')&&strchr(buffer,'n')&&strchr(buffer,'t')&&strchr(buffer,'('))
{
func_print(buffer);
}
else if(strstr(buffer,"func"))
{
save_func(buffer,fp);
}
else if((!strstr(buffer,"assign"))&&strchr(buffer,')')&&strchr(buffer,'(')&&(!strstr(buffer,"read")))
{
use_func(buffer);
}
else if(strchr(buffer,'}'))
{
}
// 赋值语句
else if(!strchr(buffer,'}'))
{
operate(buffer);
}
here:;
}
// printf("读取完成\n");
// 读取变量值验证
// visit();
if(fclose(fp))
{
printf("无法关闭文件\n");
return NO;
}
free(buffer);
return OK;
}
operate_buffer函数原型为:
void operate_buffer(char *buffer);
用于删去开头的空格。
变量定义要求
变量名: 字母数字或$组成,不能以数字开头,最多 32 字符,如 Dian2020,$1 都是合法变量名。
变量定义:
int a,b,c; float d,e; string f; int arri[16]; |
定义后数值类型默认值 0,字符串默认值“”(空串)。
变量类型有 int 整数,float 浮点数,string 字符串。
变量不存在作用域,一旦定义全局有效。
变量类型 变量名 1[,变量名 2][,变量名 3]…[,变量名 n]; 数组定义:
数组为固定长度,下标从 0 开始,默认值同变量类型默认值。
HASH-变量储存
在头文件中,我们使用hash函数在变量名和代表变量的数值之间进行映射。鉴于文件中涉及的变量少,懒惰的我直接从网上嫖了一个hash函并且没有考虑变量重名的情况。为此我表示忏悔,承诺在下一篇发之前好好学习hash函数的操作之后写总结。
我嫖的函数是这样的(HASHSIZE定义为101):
int hash(char *s)
{
int h=0;
for(;*s;s++)
h=*s+h*31;
return h%HASHSIZE;
}
变量结构体定义为:
struct variable
{
char name[33];
// type=1(int),type=2(float),type=3(string)
// type=11(int array),type=22(float array)
int type;
float x_f;
int x_i;
char *str_head;
int *array_i;
float *array_f;
};
其中,char name[33]用于存放变量名,主要是为了debug时方便查看比如变量“重名”(不同变量hash值相同)的情况。
同样鉴于涉及变量不多,我们设置全局变量:
struct variable var[101]
语句处理
对于文件中变量定义式:
int a,b,c[10];
*buffer中,int是进入read_int进行变量定义的标志。对于定义非数组,只需让该变量的type=1即可;对于数组,需要type=11的同时给int数组头指针array_i分配大小为数组下标的空间。
read_int:
void read_int(char *buffer)
{
int poi;
// 只存在一个变量
if(!strchr(buffer,','))
{
if(!strchr(buffer,'['))
{
// 非数组int
poi=write_name(strchr(buffer,' ')+1,strchr(buffer,';')-1);
write_type_int(poi);
}
else
{
// int数组
poi=write_name(strchr(buffer,' ')+1,strchr(buffer,'[')-1);
// write_type_int(poi);
creat_array_int(strchr(buffer,'[')+1,strchr(buffer,']')-1,poi);
}
}
else
{
char *begin=NULL;
char *end=NULL;
begin=strchr(buffer,' ');
end=strchr(buffer,',');
do
{
poi=write_name(begin+1,end-1);
write_type_int(poi);
// 找下一个,
*end='#';
begin=end;
if(!strchr(buffer,','))
{
end=strchr(buffer,';');
poi=write_name(begin+1,end-1);
write_type_int(poi);
break;
}
else end=strchr(buffer,',');
}while(1);
}
}
write_name函数用于将变量名写入变量结构体中,同时返回变量hash值。
write_type_int函数用于初始化变量的type。
create_array_int用于初始化数组。
float的实现与int相同,而实现string只需将字符串初始化为空串即可,不必赘述。
THE END
下次变量赋值操作!!!
话说大家有啥时间管理大法教教我呗!我最近好颓废,鬼畜区快被我看穿了。
欢迎大家批评指正!!!优化代码啊或者错误啥的。