【编译原理实验】词法分析器程序设计
1. 实验内容
设计、编制并调试一个简单语言CP(Compiler Principle)的词法分析程序,加深对词法分析原理的理解。
CP语言的词法:
(1) 关键词: begin end if then else for while do and or not
注意:所有关键词都是小写的。
(2) 标识符ID,与标准C语言一致,即:以下划线或字母开头的字母数字下划线组成的符号串。
(3)无符号整数NUM:数字串
(4)运算符和分界符: +、-、*、/、>、<、=、:=、>=、<=、<>、++、--、(、)、; 、 #
注意::=表示赋值运算符、#表示注释开始的部分,;表示语句结束,<>表示不等关系
(5)空白符包括空格、制表符和换行符,用于分割ID、NUM、运算符、分界符和关键词,词法分析阶段要忽略空白符。
2. 实验要求
(1) 给出各类单词符号的分类编码。
(2) 词法分析程序应该能发现输入串中的错误。
(3) 词法分析作为单独一遍,将词法分析程序输出的二元式序列保存为中间文件形式。
3. 设计思路
先给各类单词符号编码(见下图),以文档的形式输入将要识别的符号串,并将其存放在一个数组中,从前往后,每次根据识别到的第一个字符X做出如下操作:
(1)X为空白符:跳过X继续往下判断。
(2)X为注释符:识别注释符#,跳过其后的字符直到跳过换行符结束。
(3)X为数字符:记录此字符及其后面的字符直到遇到一个非数字符,若该非数字符为空白符、运算符或分界符,则将记录的这一段识别为数字串;否则,继续往后记录直到遇到空白符、运算符或分界符,并将记录的这一段识别为错误单词。
(4)X为运算符:判断X和其后的一个字符是否能组成运算符,若能则将X和其后的字符组合识别成运算符,否则直接识别X为运算符。
(5)X为字母符或下划线:记录此字符及其后面的字符直到遇到空白符、运算符或分界符,若记录的符号串能匹配到关键词,则将其识别为关键词,否则将其识别为标识符。
(6)X为其他符:识别为错误输入。
重复上述操作直到识别完整个输入串。

4. 程序结构
(1)主要数据结构:
字符数组:用于记录输入串。
map容器:记录各类单词符号及其编码,方便后续查找。
string类型变量:用于记录中间单词,方便处理。
(2)函数定义:
void map_init():初始化map容器,存入各类单词及其编码。
int check_num(char a):检测字符a是否是数字符。
int check_letter(char a):检测字符a是否是字母符或下划线。
int check_devide(char a):检测字符a是否是空白符、运算符、分节符或注释符。
int main():主体程序。
(3)算法流程:

5. 实验代码
#include<bits/stdc++.h> using namespace std; char ch[200]; map<string,int> mp; void map_init()//放入所有单词及编号 { mp["begin"]=0;mp["end"]=1;mp["if"]=2; mp["then"]=3;mp["else"]=4;mp["for"]=5; mp["while"]=6;mp["do"]=7;mp["and"]=8; mp["or"]=9;mp["not"]=10;mp["+"]=11; mp["-"]=12;mp["*"]=13;mp["/"]=14; mp[">"]=15;mp["<"]=16;mp["="]=17; mp[":="]=18;mp[">="]=19;mp["<="]=20; mp["<>"]=21;mp["++"]=22;mp["--"]=23; mp["("]=24;mp[")"]=25;mp[";"]=26; mp["#"]=27; } int check_num(char a)//检查是否是数字 { if(a>='0'&&a<='9') return 1; else return 0; } int check_letter(char a)//检查是否是字母 { if((a>='a'&&a<='z')||(a>='A'&&a<='Z')||(a=='_')) return 1; else return 0; } int check_devide(char a)//检测是否是运算符或分隔符 { if(a=='\n'||a=='\t'||a==' '||a=='+'||a=='-'||a=='*'|| a=='/'||a=='>'||a=='<'||a=='='||a==':'||a=='('|| a==')'||a==';'||a=='#') { return 1; } else return 0; } int main() { FILE *fp; fp=fopen("test8.txt","r"); if(fp==NULL) { cout<<"Open Error"; exit(1); } ofstream ofs; ofs.open("result8.txt",ios::out); int len=0; while(fscanf(fp,"%c",&ch[len])!=EOF) len++; fclose(fp); string temp=""; map_init(); for(int i=0;i<len;i++) { temp=""; if(ch[i]=='\n'||ch[i]=='\t'||ch[i]==' ') continue; //跳过换行符、制表符和空格 else if(ch[i]=='#') //跳过注释 { cout<<"<#,27>"<<endl; ofs<<"<#,27>"<<endl; while(ch[i]!='\n') i++; } else if(check_num(ch[i])) //检测数字串 { while(check_num(ch[i])) { temp+=ch[i]; i++; } if(check_devide(ch[i])||i>=len)//处理到分隔符或结尾 { cout<<'<'<<temp<<','<<"29"<<'>'<<endl; ofs<<'<'<<temp<<','<<"29"<<'>'<<endl; i--;//不跳过当前字符 } else { while(!check_devide(ch[i]))//跳到下一个开始位置 { temp+=ch[i]; i++; } cout<<"Error:"<<temp<<endl; ofs<<"Error:"<<temp<<endl; i--; } } else if(check_devide(ch[i]))//检测运算符 { temp+=ch[i]; map<string,int>::iterator iter=mp.find(temp); if(check_devide(ch[i+1])) { string temp1=temp+ch[i+1]; map<string,int>::iterator iter1=mp.find(temp1); if(iter1!=mp.end()) { cout<<'<'<<temp1<<','<<iter1->second<<'>'<<endl; ofs<<'<'<<temp1<<','<<iter1->second<<'>'<<endl; i++; } else { cout<<'<'<<temp<<','<<iter->second<<'>'<<endl; ofs<<'<'<<temp<<','<<iter->second<<'>'<<endl; } } else { ofs<<'<'<<temp<<','<<iter->second<<'>'<<endl; cout<<'<'<<temp<<','<<iter->second<<'>'<<endl; } } else if(check_letter(ch[i]))//检测标识符或关键字 { while(!check_devide(ch[i])&&i<len) { temp+=ch[i]; i++; } i--; map<string,int>::iterator iter=mp.find(temp); if(iter!=mp.end()) { cout<<'<'<<temp<<','<<iter->second<<'>'<<endl; ofs<<'<'<<temp<<','<<iter->second<<'>'<<endl; } else { cout<<'<'<<temp<<','<<"28"<<'>'<<endl; ofs<<'<'<<temp<<','<<"28"<<'>'<<endl; } } else { cout<<"Error:undefined"<<endl; ofs<<"Error:undefined"<<endl; } } ofs.close(); return 0; }

浙公网安备 33010602011771号