实验一:词法分析设计
1.[实验目的]:
1.了解词法分析的主要任务。
2. 熟悉编译程序的编制。
[实验内容]:根据某文法,构造一个基本词法分析程序。找出该语言的关键字、标识符、整数以及其他一些特殊符号,给出单词表(内容包括单词种类和值),构造符号表(内容包括name、kind、value和address等)。
2.C 语言文法
G[<程序>]:
<程序>→main(){<声明部分><语句部分>}
<声明部分>→<声明部分><常量声明部分>| <声明部分><变量声明部分>|<空>
<常量声明部分>→const<常量定义>{,<常量定义>};
<常量定义>→<类型> <标识符>=<无符号整数>;
<无符号整数>→<数字>{<数字>}
<变量声明部分>→<类型><标识符>{,<标识符>};
<类型>→int|float|double|long|long long|char|bool
<标识符>→<字母>{<字母>|<数字>}
<语句部分>→<条件语句>|<while循环语句>|<for循环语句>|输入语句|输出语句|复合语句|<赋值语句>
<条件语句>→if (<表达式>) <语句>;|if(<表达式>) else <语句>;
<while循环语句>→while(<表达式>){<语句>}
<for循环语句>→for(<表达式>;<表达式>;<表达式>){<语句>}
<复合语句>→{<语句部分>}
<赋值语句>→<表达式>
<表达式>→<标识符>=<算数表达式>|<布尔表达式>
<布尔表达式>→<算数表达式>|<算数表达式><关系运算符><算术表达式>
<关系运算符>→<|>|==|!=|>=|<=
<算数表达式>→<算数表达式>+<项>|<算数表达式>-<项>|<项>
<项>→<项>*<因子>|<项>/<因子>|<因子>
<因子>→<标识符>|<无符号整数>|(<算数表达式>)|true|false
<字母>→a|b|…|z|A|B|…|Z
<数字>→0|1|2|3|4|5|6|7|8|9
3.单词分类情况表
4.状态转换图
5.程序设计
词法分析程序
1 #include <cstdio> 2 #include <stdio.h> 3 #include <cctype> 4 #include <cstring> 5 #include <iostream> 6 #include <map> 7 using namespace std; 8 const string keyWord[20]= {"main","const","int","float","double","long","long long","char","while","for","if","else","false","true"}; 9 const string relSign[10]= {">","<",">=","<=","!=","==","="}; 10 11 struct signTable//符号表 12 { 13 string name; 14 int value; 15 int kind; 16 int address; 17 }record[520]; 18 map<string,bool>mpk; 19 map<string,bool>mpr; 20 int cnt = 0,num = 0; 21 const char *p; 22 void init()//建立关键字表 23 { 24 for (int i = 0; i < 14; i++) 25 mpk[keyWord[i]] = true; 26 for (int i = 0; i < 7; i++) 27 mpr[relSign[i]] = true; 28 cnt = 0,num = 0; 29 } 30 void alpha()//识别标识符 31 { 32 char save[250]; 33 int i = 0; 34 string s ; 35 while(isalnum(*p)) 36 { 37 save[i++]=*p; 38 p++; 39 } 40 save[i] = '\0'; 41 s = save; 42 p--; 43 if(mpk[s])//判断是否存在于关键字表中 44 cout<<++cnt<<" keyword "<<s<<endl; 45 else 46 { 47 record[num++].name = s; 48 cout<<++cnt<<" captionsign "<<s<<endl; 49 } 50 } 51 void digit()//识别数字 52 { 53 int i = 0; 54 char save[250]; 55 string s; 56 while(isdigit(*p)) 57 { 58 save[i++] = *p; 59 p++; 60 } 61 save[i] = '\0'; 62 s = save; 63 p--; 64 cout<<++cnt<<" digit "<<s<<endl; 65 } 66 void isRelSign()//识别关系运算符 67 { 68 char save[10]; 69 string s; 70 int i = 0; 71 while(i <= 1) 72 { 73 save[i++]=*p; 74 p++; 75 } 76 p--; 77 save[i] = '\0'; 78 s = save; 79 if(mpr[s])//判断是否存在于关系运算符表中 80 cout<<++cnt<<" relationsign "<<s<<endl; 81 else 82 { 83 p--; 84 if(*p=='!') 85 cout<<++cnt<<" error "<<*p<<endl; 86 else 87 cout<<++cnt<<" relationsign "<<*p<<endl; 88 } 89 } 90 int main() 91 { 92 string name,str,s,s1; 93 char ss[1020],filename[20]; 94 cout<<"please input your program's filename:"<<endl; 95 init(); 96 cin>>name; 97 name+=".txt";//添加扩展名 98 int len = name.size(); 99 name.copy(filename,len,0); 100 filename[len]='\0'; 101 freopen(filename,"r",stdin);//读文件 102 while(gets(ss)) 103 { 104 s1 = ss; 105 cout<<s1<<endl;//输出源程序 106 str+=s1; 107 } 108 p = str.data(); 109 while(*p!='\0') 110 { 111 while(*p==' '||*p=='\n'||*p=='\t') p++; 112 if(isalpha(*p)) alpha();//判断标识符 113 else if(isdigit(*p)) digit();//判断数字 114 else if (*p=='('||*p==')'||*p=='{'||*p=='}'||*p==','||*p==';')//判断界符 115 cout<<++cnt<<" boundarysign "<<*p<<endl; 116 else if (*p=='+'||*p=='-'||*p=='*'||*p=='/')//判断算数运算符 117 cout<<++cnt<<" arithmaticsign "<<*p<<endl; 118 else if(*p=='>'||*p=='<'||*p=='='||*p=='!')//判断关系运算符 119 isRelSign(); 120 else 121 cout<<++cnt<<" error "<<p<<endl;//出错处理 122 p++; 123 } 124 fclose(stdin);//关闭文件 125 return 0; 126 }
(1) 用map容器存储关键字和关系运算符,map容器内部是用红黑树实现的,查找效率为O(ln(N)),查找效率较高。
(2) 用结构体数组来存储符号表。因为每个符号都有多种属性,用结构体可以将这些属性封装到一起。
6.源程序代码
main()