模拟词法分析器,把读入的字符串,识别为一个个词法单元并输出。
对应语言关键字 else if int return void while
专用符号 + - * / < <= > >= == != = ; , ( ) [ ] { } /* */
首先理清思路:需要做什么?
1 从输入文件读取字符 。
2 识别字符,这个识别过程应该是循环的。
3 输出识别结果。
------------------------------------------------------
怎么读:词法分析需要我们一个一个的读入字符
这里使用fgetc(FILE*file)函数。
-----------------------------------------------------
怎么识别:对接收的字符进行处理,这里需要识别
的结果有:数字,操作符,标识符,函数名,保留字,
注释,不能识别。这些可以存在一个字符型指针数组中。
如何开始识别数字:读入一个 '0'~‘9’之间的字符
如何开始识别操作符,标识符,函数名,保留字,注释,
读入一个字母,如果这个字母是'/',开始识别注释,如果是
操作符中的字符,那么开始识别操作符,如果是其他,开始识别
标识符与函数名。
------------------------------------------------------
怎么输出,这里使用格式:<RESERVED,INT>
在文件中输出用 fprintf(FILE*file,s)
-----------------------------------------------------
打印部分代码:
void console_print(int i,int start_pos,int end_pos){ cout<<"<"<<<","; fprintf(output,"%c%s%c","<",token[i],","); int length=end_pos-start_pos; //识别的串的长度 fseek(input,-length,1); //fseek(input,start_pos,0); //移动位置太多 /********************** 要打印识别的串,首先要把 读取文本的文件指针的位置 回退到,串的开始位置。 source:文件指针 length:移动偏移,负数为 向左偏移 1:此部分有三个参数可选 0:从文件的开始位置移动 1:从文件的当前位置移动 2:从文件的结束位置移动 **********************/ char temp; for(int j=start_pos;j ",'/n'); cout<<">"<
/**********************************************fucntion: file_print(int i,int start_pos,int end_pos) parameter: @i:在字符指针数组中的索引,代表识别的类型 @start_pos: 要打印的串在文件中的开始位置 @end_pos: 要打印的串在文件中的结束位置 usage: 在文件中打印识别的串 format: 打印样例:分开打印会存在问题,当调用cosole_print后,又要重新调整文件指针,较为麻烦 写完之后发现,又注释掉,把此部分合道cosole_print中 void file_print(int i,int start_pos,int end_pos){ int length=end_pos=start_pos; //写完代码测试发现出错,应为减号 fseek(input,-length,1); fprintf(output,"<%s, ",token[i]); for(int j=start_pos;j \n");}
在get_number()中调用,打印
console_print(i,start_pos,end_pos);file_print(i,start_pos,end_pos);
这样存在的问题是,当调用console_print后,文件的指针与最初调用console时原来相比又有变化,
在file_print时,需要重新改动代码,如果是与console_print中一样的计算方法,就会出现问题,
为简单方便,直接把file_print()中的代码中合并到console_print()中。
get_comment()识别注释
void get_comment(char ch){ start_pos=ftell(input)-1; //记录开始位置 state=0; while(!feof(input)){ //若基于读入的字符分类,则比较麻烦 //需要回吐字符判断 switch(state){ case 0: state=1; ch=fgetc(input); break; case 1: if(ch=='*'){ state=2; ch=fgetc(input); } else //紧跟着'/'的不是'*'说明不是注释 ,根据定义只能是操作符 { if(ch=='\n') fseek(input,-2,1); else fseek(input,-1,1); //回退一个字符到结束位置 ,打印操作符 / end_pos=ftell(input); console_print(1,start_pos,end_pos); file_print(1,start_pos,end_pos); return; } break; case 2: if(ch=='`'){ end_pos=ftell(input); console_print(3,start_pos,end_pos); file_print(3,start_pos,end_pos); } //程序读取时候遇到一点问题,这里加一个"`"作为技术符号 else if(ch=='/'){ //如果是'/'检查是否为注释的结束 fseek(input,-2,1); //回退到'/'前面的位置,检查是否为* char temp=fgetc(input); //system("pause"); if(temp=='*'){ //如果是则结束对注释的识别,打印注释部分 fseek(input,1,1); end_pos=ftell(input); console_print(3,start_pos,end_pos); file_print(3,start_pos,end_pos); return; } else{ //否则继续识别 fseek(input,1,1); ch=fgetc(input); } } else{ ch=fgetc(input); } break; } } }
这里起初用转化输入字符的方式,但是太麻烦,需要频繁的回吐字符,判断是否到达条件
因此用转换状态的方法。其次是在代码中有很多的选择结构,要注意文件指针的位置。
get_id识别标识符(保留字,函数名,变量名)
void get_id(char ch){ start_pos=ftell(input)-1; state=0; int end=0; while(!feof(input)){ if(!is_letter(ch)&&!is_number(ch)){ if(state==0){ //状态为0时,判断是否为保留字 if(ch=='\n') fseek(input,-2,1); else fseek(input,-1,1); end_pos=ftell(input); char s[100]=""; fseek(input,-(end_pos-start_pos),1); for(int i=0;i
遇到的问题:
(1)
while(!is_recognized(ch)){//读取到可以识别的字符的地方 fgetc(input); // system("pause"); 检查代码时用到 }
最初的部分代码是这样的,这里存在一个问题是,
识别一个不能识别的字符后,就不能结束while循环了。
(2)
注意换行符\n的特殊性,在使用fgetc时,会把\n一块读
入,但文件指针向前移动两份位置。