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

📄 plx.cpp

📁 PLx语言的编译器。PLx语言是一种类Pascal语言
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>

#include <vector>
using namespace std;

#define LINELEN 256

/******************************************************************************\
*                                   全局类型                                   *
\******************************************************************************/

enum TOKENTYPE { TT_IDENT, TT_KEYWORD, TT_SYMBOL, TT_NUMBER };

enum KEYWORD {
	KW_AND,		KW_BEGIN,	KW_DO,		KW_ELSE,	KW_END,		KW_FALSE,
	KW_IF,		KW_INTEGER,	KW_LOGICAL,	KW_NOT,		KW_OR,		KW_PROGRAM,
	KW_REPEAT,	KW_THEN,	KW_TRUE,	KW_UNTIL,	KW_WHILE,	KW_WRITE
};

struct TOKEN {
	TOKENTYPE type;
	union {
		char *ident;
		KEYWORD keyword;
		int symbol;
		int number;
	};
	int line, col;
};

struct VAR {
	char *name;
	bool logic;
};

enum OPCODE { OP_INT, OP_HLT, OP_LIT, OP_LOD, OP_STO, OP_JMP, OP_JPC, OP_OPR };

struct INSTRUCT {
	OPCODE op;
	int n;
};

/******************************************************************************\
*                                   全局变量                                   *
\******************************************************************************/

const char *KeywordTab[] = {
	"and",		"begin",	"do",		"else",		"end",		"false",
	"if",		"integer",	"logical",	"not",		"or",		"program",
	"repeat",	"then",		"true",		"until",	"while",	"write",
	NULL
};

const char *OpcodeTab[] = {
	"INT",	"HLT",	"LIT",	"LOD",	"STO",	"JMP",	"JPC",	"OPR"
};

FILE *SourceFile;
char LineBuf[LINELEN], *LinePtr;
int LineNum, ColNum;
int ErrNum;
TOKEN Token;

vector<char*> IdentTab;
vector<VAR> VarTab;
vector<INSTRUCT> InstTab;

int ProgCount;
vector<int> DataStack;
bool Pause;

/******************************************************************************\
*                                 输出出错信息                                 *
\******************************************************************************/

void ErrMsg(const char *msg, int line = 0, int col = 0)
{
	if(line == 0) line = Token.line, col = Token.col;
	printf("Line %04d:\t%s\n\t\t", line, LineBuf);
	while(col)
	{
		printf(" ");
		col--;
	}
	printf("^ %s\n", msg);
	ErrNum++;
}

/******************************************************************************\
*                                  词法分析器                                  *
\******************************************************************************/

void GetToken()
{
	for(;;)
	{
		if(*LinePtr == '\0')	// 读新的一行源文件
		{
			if(fgets(LineBuf, LINELEN, SourceFile) == NULL)
			{
				ErrMsg("遇到意外的文件结束", LineNum, ColNum);
				throw new int;
			}
			char *p = LineBuf;
			while(*p && *p <= ' ') p++;
			strcpy(LineBuf, p);	// 去除行首的空白字符
			p = strchr(LineBuf, '\n');
			if(p) *p = 0;	// 去除行尾的换行符

			LinePtr = LineBuf;
			LineNum++; ColNum = 0;
		}
		else if(*LinePtr <= ' ')	// 跳过空白字符
		{
			if(*LinePtr == '\t')	// 空白字符是Tab则调整列号到下一个制表位
				ColNum += 8 - ColNum % 8;
			else
				ColNum++;
			LinePtr++;
		}
		else if(isdigit(*LinePtr))
		{
			int num = 0;
			Token.type = TT_NUMBER;
			Token.line = LineNum; Token.col = ColNum;
			do {
				num = num * 10 + (*LinePtr++ - '0');
				ColNum++;
			} while(isdigit(*LinePtr));
			Token.number = num;
			break;
		}
		else if(isalpha(*LinePtr))	// 标识符(也可能是关键字)
		{
			char buf[LINELEN], *p = buf;
			const char **q;
			while(isalpha(*LinePtr) || isdigit(*LinePtr))
				*p++ = tolower(*LinePtr++);	// 转换为小写字符(大小写不敏感)
			*p = 0;
			for(q = KeywordTab; *q && strcmp(buf, *q); q++);
			if(*q)
			{
				Token.type = TT_KEYWORD;	// 是关键字
				Token.keyword = KEYWORD(q - KeywordTab);
			}
			else
			{
				Token.type = TT_IDENT;	// 是标识符
				for(vector<char*>::iterator i = IdentTab.begin(); i != IdentTab.end() && strcmp(*i, buf); i++);
				if(i == IdentTab.end())
				{
					Token.ident = new char[p - buf + 1];
					strcpy(Token.ident, buf);
					IdentTab.push_back(Token.ident);
				}
				else
					Token.ident = *i;
			}
			Token.line = LineNum; Token.col = ColNum;
			ColNum += p - buf;
			break;
		}
		else	// 运算符、分隔符
		{
			int symbol = 0;
			switch(*LinePtr)
			{
			case ',':
			case ';':
			case '.':
			case '(':
			case ')':
			case '+':
			case '-':
			case '*':
			case '=':
				symbol = *LinePtr;
				break;
			case ':':
				if(LinePtr[1] == '=') symbol = ':=';
				break;
			case '/':
				if(LinePtr[1] == '=') symbol = '/=';
				else symbol = '/';
				break;
			case '<':
				if(LinePtr[1] == '=') symbol = '<=';
				else symbol = '<';
				break;
			case '>':
				if(LinePtr[1] == '=') symbol = '>=';
				else symbol = '>';
				break;
			}
			if(symbol)
			{
				Token.type = TT_SYMBOL;
				Token.symbol = symbol;
				Token.line = LineNum; Token.col = ColNum;
				if(symbol > 255)
					LinePtr += 2, ColNum += 2;	// 双字符
				else
					LinePtr++, ColNum++;	// 单字符
				break;
			}
			ErrMsg("非法字符", LineNum, ColNum);
			LinePtr++; ColNum++;
		}
	}
}

bool OpenSourceFile(const char *filename)
{
	if((SourceFile = fopen(filename, "r")) == NULL)
		return false;

	LinePtr = LineBuf, LineBuf[0] = '\0';
	LineNum = 0;
	IdentTab.clear();
	GetToken();
	return true;
}

bool IsKeyword(KEYWORD kw)
{
	return Token.type == TT_KEYWORD && Token.keyword == kw;
}

bool IsSymbol(int sym)
{
	return Token.type == TT_SYMBOL && Token.symbol == sym;
}

/******************************************************************************\
*                                   代码生成                                   *
\******************************************************************************/

void NewInst(OPCODE op, int n)
{
	INSTRUCT inst = { op, n };
	InstTab.push_back(inst);
}

int CurProgCount()
{
	return InstTab.size();
}

void BackPatch(int pos, int n)
{
	InstTab[pos].n = n;
}

void PrintInst(int pos)
{
	printf("%04d\t%s%8d", pos, OpcodeTab[InstTab[pos].op], InstTab[pos].n);
}

/******************************************************************************\
*                              语法分析、语义分析                              *
\******************************************************************************/

//	在变量表中搜索指定变量并返回变量的地址。找不到则返回-1。
int FindVar(const char *name)
{
	int i;
	vector<VAR>::iterator p;
	for(i = 0, p = VarTab.begin(); p != VarTab.end() && p->name != name; i++, p++);
	if(p == VarTab.end())
		return -1;
	return i;
}

void AnalyzeDS()
{
	for(;;)
	{
		if(IsKeyword(KW_BEGIN)) break;
		if(IsKeyword(KW_INTEGER) || IsKeyword(KW_LOGICAL))
		{
			bool logic = IsKeyword(KW_LOGICAL);
			GetToken();
			for(;;)
			{
				if(Token.type == TT_IDENT)
				{
					if(FindVar(Token.ident) >= 0)
						ErrMsg("标识符重定义");
					else
					{
						VAR v = { Token.ident, logic };
						VarTab.push_back(v);
					}
					GetToken();
				}
				else
				{
					ErrMsg("缺少标识符");
					while(!(IsSymbol(',') || IsSymbol(';')))
						GetToken();
				}
				if(!IsSymbol(',')) break;
				GetToken();
			}
			if(IsSymbol(';'))
				GetToken();
			else if(IsKeyword(KW_INTEGER) || IsKeyword(KW_LOGICAL))
				ErrMsg("缺少“;”");
		}
		else
		{
			ErrMsg("缺少类型说明符");
			while(!(IsKeyword(KW_INTEGER) || IsKeyword(KW_LOGICAL) || IsKeyword(KW_BEGIN)))
				GetToken();
		}
	}
}

void AnalyzeAE();

void AnalyzeAF()
{
	if(Token.type == TT_IDENT)
	{
		int disp = FindVar(Token.ident);
		if(disp < 0)
			ErrMsg("标识符未定义");
		else if(VarTab[disp].logic)
			ErrMsg("标识符应为数值型变量");
		GetToken();
		NewInst(OP_LOD, disp);
	}
	else if(Token.type == TT_NUMBER)
	{
		NewInst(OP_LIT, Token.number);
		GetToken();
	}
	else if(IsSymbol('-'))
	{
		GetToken();
		AnalyzeAF();
		NewInst(OP_OPR, 0);
	}
	else if(IsSymbol('('))
	{
		GetToken();
		AnalyzeAE();
		if(IsSymbol(')'))
			GetToken();
		else
		{
			ErrMsg("缺少“)”");
			while(!(IsSymbol(')') || IsSymbol(';') || Token.type == TT_KEYWORD))
				GetToken();
		}
	}
	else
	{
		ErrMsg("非法表达式项");
		while(!(IsSymbol(')') || IsSymbol(';') || Token.type == TT_KEYWORD))
			GetToken();
	}
}

void AnalyzeAT()
{
	AnalyzeAF();
	while(IsSymbol('*') || IsSymbol('/'))
	{
		int sym = Token.symbol;
		GetToken();
		AnalyzeAF();
		NewInst(OP_OPR, sym == '*' ? 3 : 4);
	}
}

void AnalyzeAE()
{
	AnalyzeAT();
	while(IsSymbol('+') || IsSymbol('-'))
	{
		int sym = Token.symbol;
		GetToken();
		AnalyzeAT();
		NewInst(OP_OPR, sym == '+' ? 1 : 2);
	}
}

void AnalyzeRE()
{
	AnalyzeAE();
	if(IsSymbol('=') || IsSymbol('/=') || IsSymbol('<') || IsSymbol('<=') || IsSymbol('>') || IsSymbol('>='))
	{
		int sym = Token.symbol;
		GetToken();
		AnalyzeAE();
		switch(sym)
		{
			case '=': NewInst(OP_OPR, 8); break;
			case '/=': NewInst(OP_OPR, 9); break;
			case '<': NewInst(OP_OPR, 10); break;
			case '<=': NewInst(OP_OPR, 11); break;
			case '>': NewInst(OP_OPR, 12); break;
			case '>=': NewInst(OP_OPR, 13); break;
		}
	}
	else
	{
		ErrMsg("缺少关系运算符");
		while(!(IsSymbol(')') || IsSymbol(';') || Token.type == TT_KEYWORD))
			GetToken();
	}
}

void AnalyzeBE();

void AnalyzeBF()
{
	if(Token.type == TT_IDENT)
	{
		int disp = FindVar(Token.ident);

⌨️ 快捷键说明

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