当前位置:   article > 正文

编译原理实验(1)——词法分析器_山东大学软件学院编译原理实验

山东大学软件学院编译原理实验

编译实验——词法分析器

实验内容及要求:

  1. C计算机语言的编译程序的词法分析部分实现。
    从左到右扫描每行该语言源程序的符号,拼成单词,换成统一的内部表(token)送给语法分析程序。
    在这里插入图片描述
  2. 为了简化程序的编写,有具体的要求如下:
    (1)空白符仅仅是空格、回车符、制表符。
    (2)代码是自由格式。
    注释应放在花括号之内,并且不允许嵌套。
  3. 要求实现编译器的以下功能:
    (1)按规则拼单词,并转换成二元式形式
    (2)删除注释行
    (3)删除空白符 (空格、回车符、制表符)
    (5)发现并定位错误。

算法分析:

1.算法设计
  • 保留字采用一符一类,22个保留字,种类码0-21,存在字符串数组keyword[22]中。
  • 特殊符号也采用一符一类,种类码22-38,存在字符串数组 special[17]中。种类码39-44表示==,!=,&&,||,>=,<=
  • 八进制,十进制,十六进制整数种类码为98-100。
  • 标识符ID种类码为101。
  • 字符串常量种类码为102,字符常量种类码为103。
  • 用STL中的stack容器实现简单的括号匹配,遇到{ or (or [进栈,遇到}or)or]出栈,若最后栈不空,则输出{ or (or [不匹配。
  • 利用状态转换图,逐个处理源程序字符流中的字符,并输出单词种类码和单词形如<sym,token>
2. 状态转换图
  • 注释:
    注释

  • 标识符
    标识符
    注:若第一个输入字符为字母,则标识符和保留字的词法构成相同,为了更好的实现,把语言的保留字建立一个表格存储,这样可以把保留字的识别放在标识符之后,用识别出的标识符对比该表格,如果存在该表格中则是保留字,否则是一般标识符。

  • 八十十六进制整数进制整数

  • 制表符
    制表符

  • 空格
    在这里插入图片描述

  • 字符常量

在这里插入图片描述

  • 字符串常量
    在这里插入图片描述
  • 注释注释
3. 变量及函数解释
  • 程序定义的全局变量解释:
    source:将源程序转化为字符串存入。
    token: 识别出的单词
    p:当前正在处理的字符下标
    sym:种类码
  • 自定义的函数解释:
    void preprocess(string& source); //对源程序进行预处理,去掉注释换行符制表符,方便识别单词
    void GetToken(); //识别不同种类的单词

源代码

#include <iostream>
#include <cctype>
#include <fstream>
#include <string>
#include <stack>
using namespace std;
void preprocess(string &source);
void GetToken();
//保留字,一符一类,种类码0~21
string keyword[22] = {"if", "else", "while", "do", "break", "main", "int", "float", "double", "return", "const", "void", "continue", "char", "unsigned", "enum", "long", "switch", "case", "unsigned", "auto", "static"};
//特殊符号,一符一类,种类码22-38,种类码39-44为==,!=,&&,||,>=,<=
string special[17] = {"+", "-", ",", "/", "=", "<", ">", "{", "}", ";", "(", ")", "&", "!", "#", "[", "]"};
string source = "";
string token;
stack<char> s[3];
char ch;
int p = 0; //表示当前正在处理的字符;
int sym;   //sym表示种类码;
int main()
{
	string filename;
	cout << "输入文件名:";
	cin >> filename;
	ifstream file(filename, ios::in);
	ofstream outfile1("实验二 语法分析器/语法分析器/语法分析器/token.txt", ios::out);
	ofstream outfile2("实验三 LR分析器/token.txt", ios::out);
	if (!file)
	{
		cerr << "文件打开失败!" << endl;
		exit(1);
	}
	file.get(ch);
	do
	{
		source += ch;
		file.get(ch);
	} while (!file.eof());
	file.close();
	cout << "--------------------------------------------------------------------------------------------------------------" << endl;
	cout << "源程序:\n"
		 << source << endl;
	preprocess(source);
	cout << "--------------------------------------------------------------------------------------------------------------" << endl;
	cout << "处理后程序:\n"
		 << source << endl;
	cout << "--------------------------------------------------------------------------------------------------------------" << endl;
	do
	{
		GetToken();
		if (sym != 9999)
		{
			outfile1 << sym << " " << token << " ";
			outfile2 << sym << " " << token << " ";
		}
		if (sym == -1)
		{
			cout << "词法分析出错!" << endl;
			break;
		}
		else if (sym >= 0 && sym <= 21)
			cout << "<" << sym << "," << token << ">" << endl;
		else if (sym >= 22 && sym <= 44)
			cout << "<" << sym << "," << token << ">" << endl;
		else if (sym == 98)
			cout << "<DEC," << token << ">" << endl;
		else if (sym == 99)
			cout << "<OTC," << token << ">" << endl;
		else if (sym == 100)
			cout << "<HEX," << token << ">" << endl;
		else if (sym == 101)
			cout << "<ID," << token << ">" << endl;
		else if (sym == 102)
			cout << "<字符串常量," << token << ">" << endl;
		else if (sym == 103)
			cout << "<字符常量," << token << ">" << endl;
		//      else if (sym == 9999)
		//      {
		//          cout << "词法分析器出错!请检查是否输入非法字符" << endl; break;
		//      }
	} while (p < source.length());
	if (!s[0].empty())
		cout << "ERROR:{不匹配!" << endl;
	if (!s[1].empty())
		cout << "ERROR:[不匹配!" << endl;
	if (!s[2].empty())
		cout << "ERROR:(不匹配!" << endl;
	outfile1.close();
	outfile2.close();
	system("pause");
	return 0;
}
void GetToken()
{
	sym = 9999;
	token = "";
	ch = source[p++];
	while (ch == ' ')
		ch = source[p++];
	//识别标识符
	if (ch == '_')
	{
		sym = 101;
		do
		{
			token += ch;
			ch = source[p++];
		} while (ch == '_' || isalpha(ch) || isdigit(ch));
		p--;
	}
	//识别保留字和标识符
	else if (isalpha(ch))
	{
		sym = 101;
		do
		{
			token += ch;
			ch = source[p++];
		} while (isalpha(ch));
		int i;
		for (i = 0; i < 22; i++)
		{
			if (token == keyword[i])
			{
				sym = i;
				break;
			}
		}
		p--;
	}

	//识别各进制无符号整数
	else if (isdigit(ch))
	{
		if (ch >= '1' && ch <= '9')
		{
			sym = 98;
			do
			{
				token += ch;
				ch = source[p++];
			} while (isdigit(ch));
			p--;
		}
		else
		{
			token += ch;
			ch = source[p];
		}
		if (ch == 'x')
		{
			sym = 100;
			do
			{
				token += ch;
				ch = source[p++];
			} while (isdigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'));
			p--;
		}
		else if (ch >= '0' && ch <= '7')
		{
			sym = 99;
			do
			{
				token += ch;
				ch = source[p++];
			} while (ch >= '0' && ch <= '7');
			p--;
		}
		else
		{
			sym = 98;
		}
	}

	//识别字符串常量
	else if (ch == '"')
	{
		sym = 102;
		do
		{
			token += ch;
			ch = source[p++];
		} while (ch != '"');
		token += ch;
		ch = source[p++];
		p--;
	}
	//识别字符常量
	else if (ch == '\'')
	{
		sym = 103;
		do
		{
			token += ch;
			ch = source[p++];
		} while (ch != '\'');
		token += ch;
		ch = source[p++];
		p--;
	}

	//识别特殊符号
	else
	{
		int i = 0;
		for (i = 0; i < 17; i++)
		{
			if (ch == special[i][0])
			{
				token += ch;
				sym = i + 22;
			}
		}
		//括号匹配
		if (ch == '{')
			s[0].push(ch);
		if (ch == '[')
			s[1].push(ch);
		if (ch == '(')
			s[2].push(ch);
		if (ch == '}' && (!s[0].empty()))
			s[0].pop();
		if (ch == ']' && (!s[1].empty()))
			s[1].pop();
		if (ch == ')' && (!s[2].empty()))
			s[2].pop();
		if (ch == '=')
		{
			ch = source[p++];
			if (ch == '=')
			{
				token += ch;
				sym = 39;
			}
			else
				p--;
		}
		if (ch == '!')
		{
			ch = source[p++];
			if (ch == '=')
			{
				token += ch;
				sym = 40;
			}
			else
				p--;
		}
		if (ch == '&')
		{
			ch = source[p++];
			if (ch == '&')
			{
				token += ch;
				sym = 41;
			}
			else
				p--;
		}
		if (ch == '|')
		{
			ch = source[p++];
			if (ch == '|')
			{
				token += ch;
				sym = 42;
			}
			else
				p--;
		}
		if (ch == '>')
		{
			ch = source[p++];
			if (ch == '=')
			{
				token += ch;
				sym = 43;
			}
			else
				p--;
		}
		if (ch == '<')
		{
			ch = source[p++];
			if (ch == '=')
			{
				token += ch;
				sym = 44;
			}
			else
				p--;
		}
	}
}

void preprocess(string &source)
{
	string str = "";
	//删除注释行
	for (int i = 0; i < source.length(); i++)
	{
		if (source[i] == '/' && source[i + 1] == '/')
		{
			while (source[i] != '\n')
			{
				i++;
			}
		}
		if (source[i] == '/' && source[i + 1] == '*')
		{
			i += 2;
			while (source[i] != '*' || source[i + 1] != '/')
			{
				i++;
				if (i == source.length() - 1)
				{
					cout << "注释出错,没有找到 */,程序结束!\n";
					exit(0);
				}
			}
			i += 2;
		}
		//删除换行和制表符
		if (source[i] != '\n' && source[i] != '\t')
		{
			str += source[i];
		}
	}
	source = str;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330

输出展示:

1.输入文件case.txt内容如下:

{
	i = 2;
	while (i <= 100)
	{
		sum = sum + i;
		i = i + 2;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出如下(该输出写入token.txt作为实验二输入):
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/592951
推荐阅读
相关标签
  

闽ICP备14008679号