【编译原理课程设计】说明语句的词法分析器
题目三 说明语句的词法分析器
一、设计目的
了解词法分析程序的基本构造原理,掌握词法分析程序的手工构造及自动构造方法。
二、设计内容
根据PASCAL语言的说明语句形式,用手工及自动方法构造一个对说明语句进行词法分析的程序。该程序能对从键盘输入或从文件读入的形如:
“const count=10,sum=81.5,char1=’f’,string1=”hj”, max=169;”
的常量说明串进行处理,分析常量说明串中各常量名、常量类型及常量值,并统计各种类型常量个数。
三、设计要求
1、输入的常量说明串,要求最后以分号作结束标志;
2、根据输入串或读入的文本文件中第一个单词是否为“const”判断输入串或文本文件是否为常量说明内容;
3、识别输入串或打开的文本文件中的常量名。常量名必须是标识符,定义为字母开头,后跟若干个字母,数字或下划线;
4、根据各常量名紧跟等号“=”后面的内容判断常量的类型。其中:字符型常量定义为放在单引号内的一个字符;字符串常量定义为放在双引号内所有内容;整型常量定义为带或不带+、- 号,不以0开头的若干数字的组合;实型常量定义为带或不带+、- 号,不以0开头的若干数字加上小数点再后跟若干数字的组合;
5、统计并输出串或文件中包含的各种类型的常量个数;
6、以二元组(类型,值)的形式输出各常量的类型和值;
7、根据常量说明串置于高级语言源程序中时可能出现的错误情况,模仿高级语言编译器对不同错误情况做出相应处理。
四、运行结果
1、输入如下正确的常量说明串:
const count=10,sum=81.5,char1=‘f’,max=169,str1=“h*54 2..4S!AAsj”, char2=‘@’,str2=“aa!+h”;
输出:
count(integer,10)
sum(float,81.5)
char1(char, ‘f’)
max(integer,169)
str1(string,“h*54 2..4S!AAsj”)
char2(char, ‘@’)
str2(string,“aa!+h”)
int_num=2; char_num=2; string_num=2; float_num=1.
2、输入类似如下的保留字const错误的常量说明串:
Aconstt count=10,sum=81.5,char1=‘f’;
输出类似下面的错误提示信息:
It is not a constant declaration statement!
Please input a string again!
3、输入类似如下含常量名或常量值错误的常量说明串:
const count=10,12sum=81.5,char1=‘ff’,max=0016;
输出类似下面的错误提示信息:
count(integer,10)
12sum(Wrong! It is not a identifier!)
char1(Wrong! There are more than one char in ‘’.)
max(Wrong! The integer can’t be started with ‘0’.)
int_num=1; char_num=0; string_num=0; float_num=0.
4、其他类型的错误处理情况(略)。
五、提示
本课程设计重点有三个:一是作为常量名的标识符的识别;二是如何根据“=”后出现的内容来判断常量类型;三是对各种错误的处理。难点是对整型和实型常量的判断必须综合考虑多种可能情况。
提示:
用指针或数组与指针相结合来处理输入的常量说明串;
对整型和实型常量处理时,重点考虑常数中‘0’的位置。
六、分析与讨论
1、若考虑用E或e的科学计数法来表示整数和实数,应该如何实现?
2、若考虑布尔型常量,且规定其值只能为true或false,应该如何实现?
3、如何对手工构造的词法分析程序做进一步的优化,以提高代码质量和运行效率?
1 #include<iostream> 2 using namespace std; 3 char example[10000]; //缓冲区 4 int example_p;//缓冲区指针 5 6 char token[10];//常量名 7 int token_p;//常量名指针 8 9 char num[10000];//数据 10 int num_p;//数据指针 11 char ch; 12 13 int int_num = 0, char_num = 0, float_num = 0, string_num = 0; 14 15 //字符是字母 16 bool is_letter(char ch) { 17 if ((ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z')) 18 return true; 19 else 20 return false; 21 } 22 //字符是数字 23 bool is_digit(char ch) { 24 if (ch >= '0'&&ch <= '9') 25 return true; 26 else 27 return false; 28 } 29 30 31 //消除空格 32 void space() { 33 while (ch == ' ') { 34 example_p++; 35 ch = example[example_p]; 36 } 37 } 38 39 //const检查 40 bool inspect() { 41 int token_p = 0; 42 if (ch != 'c') 43 return false; 44 else { 45 while (is_letter(ch)) { 46 token[token_p] = ch; 47 token_p++; 48 example_p++; 49 ch = example[example_p]; 50 } 51 //const比对 52 if (strcmp(token, "const") == 0) { 53 return true; 54 } 55 else 56 return false; 57 } 58 59 } 60 61 //串扫描 将常量名存入token 数据存入num 62 void scan() { 63 memset(token, 0, sizeof(token)); //数组清零 64 memset(num, 0, sizeof(num)); 65 66 token_p = 0; 67 num_p = 0; 68 //消除空格 69 space(); 70 //获取=前的常量名存入token 71 while (ch != '=') { 72 token[token_p] = ch; 73 token_p++; 74 example_p++; 75 ch = example[example_p]; 76 } 77 if (ch == '=') { 78 example_p++; 79 ch = example[example_p]; 80 } 81 //消除空格 82 space(); 83 //获取=后的数据 存入num 字符形式存入 84 while (ch != ',') { 85 num[num_p] = ch; 86 num_p++; 87 example_p++; 88 ch = example[example_p]; 89 if (ch == ';') 90 break; 91 } 92 if (ch == ',') { 93 example_p++; 94 ch = example[example_p]; 95 } 96 97 } 98 99 //判断数据类型 100 const char* type(char* num) { 101 //字符型第一个字符为单引号 102 if (num[0] == '\'') { 103 104 return "char"; 105 } 106 //字符串型第一个字符为双引号 107 else if (num[0] == '"') { 108 109 return "string"; 110 } 111 else { 112 for (int i = 0;i < sizeof(num);i++) { 113 if (num[i] == '.') { 114 115 return "float"; 116 } 117 } 118 119 return "interger"; 120 } 121 } 122 123 124 125 int main() { 126 127 example_p = 0; 128 char str; 129 do { 130 str = getchar(); 131 example[example_p] = str; 132 example_p++; 133 } while (str != ';'); 134 135 example_p = 0; 136 ch = example[example_p]; 137 138 //测试案例 139 //const count=10,sum=81.5,char1='f',max=169,str1="h*54 2..4S!AAsj", char2='@',str2="aa!+h"; 140 //Aconstt count=10,sum=81.5,char1='f'; 141 //const count=10,12sum=81.5,char1='ff',max=0016; 142 143 if (inspect()) { 144 do { 145 scan(); 146 if (is_digit(token[0])){ 147 //变量名以数字开头 148 cout<<token<<"(Wrong! It is not a identifier!)"<<endl; 149 150 151 } 152 //字符类型有多个字符 153 else if (strcmp(type(num), "char") == 0 && sizeof(num) > 4) { 154 cout << token << "(There are more than one char in ''.)" << endl; 155 156 } 157 //整数第一个字符不能为0 158 else if (strcmp(type(num),"interger")==0&&num[0]=='0') { 159 cout<<token<<"(Wrong! The integer can’t be started with ‘0’.)"<<endl; 160 161 162 } 163 else { 164 cout << token << "(" << type(num) << "," << num << ")" << endl; 165 //统计不同类型数据的个数 166 if (strcmp(type(num), "interger") == 0) 167 int_num++; 168 else if (strcmp(type(num), "char") == 0) 169 char_num++; 170 else if (strcmp(type(num), "string") == 0) 171 string_num++; 172 else 173 float_num++; 174 } 175 //到达末尾时结束 176 } while (ch != ';'); 177 cout << endl; 178 cout << "int_num=" << int_num << " " << "char_num=" << char_num << " " << "string_num=" << string_num << " " << "float_num=" << float_num; 179 }else { 180 cout << "It is not a constant declaration statement! " << endl; 181 cout << "Please input a string again!" << endl; 182 } 183 184 system("pause"); 185 return 0; 186 }