⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 词法分析.cpp

📁 编译原理课程设计,用C写的PL/0编译器,有详细的文档和代码
💻 CPP
字号:
#include <iostream.h>
#include <fstream>
#include <stdlib.h>
#include <string>
using namespace std;

#define	norow	13	//保留字的个数
#define nmax	14	//数字允许的最长位数
#define al		10	//标识符最长长度

fstream	 infile;		//源文件

char	ch;			//存放最近一次从文件中读出的字符
string sym;			//存放最近一次识别出来的保留字的类型
string id;			//存放最近一次识别出来的标识符的名字
int		num;		//存放最近一次识别出来的数字的值
int		cc;			//行缓冲区指针
int		ll;			//行缓冲区长度
int		kk;
char	line[81];	//行缓冲区,用于从文件读出一行
char	a[al];			//词法分析器中用于临时存放正在分析的词
string  word[norow+1];	//保留字表
string  wsym[norow+1];	//保留字表中每一个保留字对应的symbol类型
string  ssym['^'];		//一些符号对应的symbol类型表
char    fname[20];		//PL/0语言源程序

void error(int a) {
}
	
void getch() {		//读取一个字符
	if (cc==ll) {	//如果行缓冲区指针指向行缓冲区最后一个字符就从文件读一行到行缓冲区
		if (infile.eof()) {		 //文件结束
			exit(0);
		}
		ll=0;
		cc=0;
		infile.getline(line,sizeof(line));	//读取一行
		int i=0;
		while (line[i]!=NULL) {
			ll++;
			i++;
		}
		line[ll]='\n';
		cc--;
	}
	cc++;
	ch=line[cc];
}

void getsym() {		//语法分析
	int k;
	while (ch==' '||ch=='\n') {
		getch();		
	}
	if (ch>='a'&&ch<='z') {		//如果读出的字符是一个字母,说明是保留字或标识符
		k=0;					//标识符缓冲区指针置0
		for (int j=0;j<al;j++) {//初始化a数组,使里面的内容全部为空
			a[j]=NULL;
		}
		while ((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')) {			
			if (k<al) {			//如果标识符长度没有超过最大标识符长度(如果超过,就取前面一部分,把多余的抛弃
				a[k]=ch;
				k++;
			}
			getch();
		}
		id=a;
		for (int i=0;i<norow;i++) {
			if (word[i]==id) {
				sym=wsym[i];
				break;
			}
		}
		if (i==norow) {
			sym="ident";
		}
	}
	else if (ch>='0'&&ch<='9') {		//如果读出字符是数字
		k=0;			//数字位数
		num=0;			//数字置为0
		sym="number";		//置sym为number,表示这一次读到的是数字
		while (ch>='0'&&ch<='9') {
			num=10*num+ch-'0';
			k++;		//数字位数加1
			getch();
		}
		id=num;
		if (k>nmax) {	//如果组成的数字位数大于最大允许的数字位数
			error(30);
		}
	}
	else if (ch==':') {			//如果读出的不字母也不是数字而是冒号
		getch();
		if (ch=='=') {			//赋值号
			sym="becomes";
			id=":=";
			getch();
		}
		else					//错误
			sym="NULL";
	}
	else if (ch=='<') {			//如果读到小于号
		getch();
		if (ch=='=') {			//<=号
			sym="leq";
			id="<=";
			getch();
		}
		else {
			sym="lss";			//<号
			id="<";
		}
	}
	else if (ch=='>') {			//如果读到大于号,处理过程类似于处理小于号
		getch();
		if (ch=='=') {			//>=号
			sym="geq";
			id=">=";
			getch();
		}
		else {
			sym="gtr";			//>号
			id=">";
		}
	}
	else {				//说明是一个普通的符号,从符号表中找,并给sym值
		sym=ssym[ch];
		id=ch;
		getch();
	}
}


void main() {
	//这个循环把ssym数组全部填"NULL"
	for (ch=0;ch<='^';ch++) {
		ssym[ch]="NULL";
	}
	//初始化保留字
	word[0]="begin";
	word[1]="call";
	word[2]="const";
	word[3]="do";
	word[4]="end";
	word[5]="if";
	word[6]="odd";
	word[7]="procedure";
	word[8]="read";
	word[9]="then";
	word[10]="var";
	word[11]="while";
	word[12]="write";
	//初始化保留字符号列表
	wsym[0]="beginsym";
	wsym[1]="callsym";
	wsym[2]="constsym";
	wsym[3]="dosym";
	wsym[4]="endsym";
	wsym[5]="ifsym";
	wsym[6]="oddsym";
	wsym[7]="procsym";
	wsym[8]="readsym";
	wsym[9]="thensym";
	wsym[10]="varsym";
	wsym[11]="whilesym";
	wsym[12]="writesym";
	//初始化符号表,把可能出现的符号赋上相应的类型,其余符号由于开始处的循环所赋的类型均为"null"
	ssym['+']="plus";
	ssym['-']="minus";
	ssym['*']="times";
	ssym['/']="slash";
	ssym['(']="lparen";
	ssym[')']="rparen";
	ssym['=']="eql";
	ssym[',']="comma";
	ssym['.']="period";
	ssym['#']="neq";
	ssym[';']="semicolon";

	cc=0;		//词法分析行缓冲区指针置0
	ll=0;		//词法分析行缓冲区长度置0
	ch=' ';		//词法分析当前字符为空格
	kk=al;		//置kk的值为允许的标识符的最长长度
	
	cout<<"请输入源文件名:"<<endl;
	cin>>fname;
	infile.open(fname);		
	if (!infile) {
		cout<<"没有找到文件 "<<fname<<endl;
	}
	while (1) {
		getsym();
		if (sym=="number") {
			cout<<num<<"    "<<sym.data()<<endl;
		}
		else {
			cout<<id.data()<<"   "<<sym.data()<<endl;
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -