编译原理 | 课程设计 — PL/0编译程序语法分析

1、任务描述

基于第二章的词法分析程序,使用C/C++语言编写PL/0编译程序的语法分析程序。

2、编程要求

完成上述编程任务,将C/C++语言源程序复制粘贴到右侧代码编辑器,点击“评测”按钮,运行程序,系统会自动进行结果对比。

3、测试说明

平台会对你编写的代码进行测试:

测试输入:

const a = 10;
var   b, c;
procedure p;
    if a <= 10 then
        begin
            c := b + a;
        end;
begin
    read(b);
    while b # 0 do
        begin
            call p;
            write(2 * c);
            read(b);
        end;
end.

预期输出:

语法正确

测试输入:

const a := 10;
var   b, c;
procedure p;
    if a <= 10 then
        begin
            c := b + a;
        end;
begin
    read(b);
    while b # 0 do
        begin
            call p;
            write(2 * c);
            read(b);
        end;
end.

预期输出:

(语法错误,行号:1)

测试输入:

const a = 10;
var   b, c;
//单行注释
/*
* 多行注释
*/
procedure p;
    if a <= 10 then
        begin
            c := b + a
        end;
begin
    read(b);
    while b # 0 do
        begin
            call p;
            write(2 * c);
            read(b);
        end;
end.

预期输出:

(语法错误,行号:13)

测试输入:

扫描二维码关注公众号,回复: 15344483 查看本文章
const a = 10;
var   b, c;
//单行注释
/*
* 多行注释
*/
procedure p;
    if a <= 10 then
        begin
            c := b + a;
        end;
begin
    read(b);
    while b # 0
        begin
            call p;
            write(2 * c);
            read(b);
        end;
end.

预期输出:

(语法错误,行号:17)

测试输入:

const a := 10;
var   b, c d;
//单行注释
/*
* 多行注释
*/
procedure procedure fun1;
    if a <= 10 
        begin
            c = b + a
        end;
begin
    read(b;
    while b # 0 
        begin
            call fun1;
            write 2 * c);
            read(b);
        end;
end.

预期输出:

(语法错误,行号:1)
(语法错误,行号:2)
(语法错误,行号:10)
(语法错误,行号:11)
(语法错误,行号:13)
(语法错误,行号:16)
(语法错误,行号:17)
(语法错误,行号:20)

4、代码 

        语法分析的代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include <iostream>
#include <sstream>
using namespace std;

/* ------------ 全局变量声明定义 ------------ */
int lineNumber = 1; // 当前行号

char charTable[2000];				// 字符表 —— 存储输入程序的 所有字符,包括空格、换行等
string wordTable[200] = { "\0" };	// 单词表 —— 存储输入程序的 所有单词,包括换行
char word[88] = "\0";				// 存储单个字符,添加到 wordTable 中

string ENDsign = "end.";	// 结束标识符
int charIndex = 0;			// 记录当前 charTable 字符个数
int wordIndex = 0;			// 记录当前 wordTable 单词个数

int errorNum = 0;			// 语法错误个数
int errorLine = 0;			// 语法错误行

string reservedWord[20] = { // 保留字
	"begin","call", "const","do","end","if",
	"odd","procedure", "read","then",
	"var","while","write"
};


/* ------------ 函数声明 ------------ */
void LexicalAnalysis();		// 词法分析
void GrammaticalAnalysis();	// 语法分析

void StrConnect(char* str, char ch);	// 拼接字符串
int StrLength(char* str);			// 计算字符串长度

int IsChar(char ch);			// 判断是否是字符
int IsOperator(char ch);		// 判断是否是运算符
int IsDigit(char ch);			// 判断是否是数字
int IsBoundary(char ch);		// 判断是是否界符
int IsReservedWord(char* str);	// 判断是否是保留字

void ProcessString(char ch);	// 判断字符串是否合法,合法则保存到单词表中
void ProcessNumber(char ch);	// 判断数字串是否合法,合法则保存到单词表中

void PrintError(int type);		//语法错误输出

int id();					// 变量名声明判断
void subroutine();			// 子程序
void constant();		// 常量定义
void variable();		// 变量定义
void sentence();			// 语句分析
void annotation();			// 注释
void condition();			// 条件分析
void expression();			// 表达式
void term();				// 项
void factor();				// 因子
void identifier();			// 标识符
void number();				// 数字



/* ------------ 函数定义 ------------ */
// 词法分析
void LexicalAnalysis() {
	while (charTable[charIndex] != '\0') { // 当前字符表未识别到结束符 '\0'
		if (charTable[charIndex] == '\0')
			break;
		if (charTable[charIndex] == ' ') {
			charIndex++;
			continue;
		}
		if (charTable[charIndex] == '\n') {
			wordTable[wordIndex++] = "\n";  // 将 换行符 保存到单词表 wordTable 中
			charIndex++;
			lineNumber++;	// 程序换行,行数加一
		}
		// 识别到字符
		else if (IsChar(charTable[charIndex])) {
			ProcessString(charTable[charIndex]); // 处理该字符之后的字符串
			continue;
		}
		// 识别到数字
		else if (IsDigit(charTable[charIndex])) {
			ProcessNumber(charTable[charIndex]); // 处理该数字之后的数字串
			continue;
		}
		// 识别到'/' 符
		else if (charTable[charIndex] == '/') {
			// 之后是 '/' ,说明是注释 //
			if (charTable[charIndex + 1] == '/') {
				wordTable[wordIndex++] = "//";
				charIndex = charIndex + 2;
				word[0] = '\0';

				while (charTable[charIndex] != '\n') // 将未换行的字符全部识别为注释
					StrConnect(word, charTable[charIndex++]);
				wordTable[wordIndex++] = word;
				wordTable[wordIndex++] = "\n";
				charIndex++;
				continue;
			}
			// 之后是 '*' ,说明是注释 /*
			else if (charTable[charIndex + 1] == '*') {
				wordTable[wordIndex++] = "/*";
				charIndex = charIndex + 2;
				while (!(charTable[charIndex] == '*' && charTable[charIndex + 1] == '/')) {
					if (charTable[charIndex] == '\n') {
						wordTable[wordIndex++] = "\n";
						charIndex++;
						continue;
					}
					word[0] = '\0';
					while (charTable[charIndex] != '\n') StrConnect(word, charTable[charIndex++]);
					wordTable[wordIndex++] = word;
					wordTable[wordIndex++] = "\n";
					charIndex++;
				}
				wordTable[wordIndex++] = "*/";
				charIndex = charIndex + 2;
				word[0] = '\0';
				continue;
			}
			// 是非法字符(串)
			else {
				while (charTable[charIndex] != ' ' && IsBoundary(charTable[charIndex]) != 1 && charTable[charIndex] != '\0') {
					StrConnect(word, charTable[charIndex]);
					charIndex++;
				}
				printf("(非法字符(串),%s,行号:%d)\n", word, lineNumber);
				word[0] = '\0';
				break;
			}
		}
		// 识别到比较符
		else if (charTable[charIndex] == '<' || charTable[charIndex] == '>') {
			charIndex++;
			// 是 <= 或者 >= 符
			if (charTable[charIndex] == '=') {
				if (charTable[charIndex - 1] == '<')
					wordTable[wordIndex] = "<="; // 保存单词表
				else
					wordTable[wordIndex] = ">="; // 保存单词表
				wordIndex++;
				charIndex++;
				continue;
			}
			// 是 < 或者 > 符
			else {
				if (charTable[charIndex - 1] == '<')
					wordTable[wordIndex] = "<"; // 保存单词表
				else
					wordTable[wordIndex] = ">"; // 保存单词表
				wordIndex++;
				continue;
			}
		}
		// 识别到':'
		else if (charTable[charIndex] == ':') {
			charIndex++;
			if (charTable[charIndex] == '=') {
				wordTable[wordIndex++] = ":="; // 保存单词表
				charIndex++;
				continue;
			}
			else {
				printf(":后面不是=号\n");
				continue;
			}
		}
		// 识别到运算符
		else if (IsOperator(charTable[charIndex])) {
			wordTable[wordIndex++] = charTable[charIndex]; // 保存单词表
			charIndex++;
			continue;
		}
		// 识别到界符
		else if (IsBoundary(charTable[charIndex])) {
			wordTable[wordIndex++] = charTable[charIndex]; // 保存单词表
			charIndex++;
			continue;
		}
		// 识别到非法字符(串)
		else {
			printf("(非法字符(串),%c,行号:%d)\n", charTable[charIndex], lineNumber);
			charIndex++;
		}
	}
}
// 语法分析
void GrammaticalAnalysis() {
	subroutine();
	if (!wordTable[wordIndex].compare(".")) {
		if (errorNum == 0)
			printf("语法正确\n");
	}
	else {
		PrintError(0); // 输出语法错误以及行号
		return;
	}
}
// 打印语法错误
void PrintError(int type) {
	if (type == 1) {
		if (errorLine != lineNumber) {
			errorLine = lineNumber;
			printf("(语法错误,行号:%d)\n", lineNumber);
			errorNum++;
		}
	}
	else {
		while (wordTable[wordIndex].compare("\n") != 0) 
			wordIndex++;
		if (errorLine != lineNumber) {
			errorLine = lineNumber;
			printf("(语法错误,行号:%d)\n", lineNumber);
			errorNum++;
		}
	}
}


// 拼接字符串
void StrConnect(char* str, char ch) {        
	int i = 0;
	while (str[i] != '\0') i++;
	str[i] = ch;
	str[i + 1] = '\0';
}
// 计算字符串长度
int StrLength(char* str) {     
	int i = 0;
	while (str[i] != '\0') 
		i++;
	return i;
}

// 判断是否是字符
int IsChar(char ch) {
	if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
		return 1;
	else
		return 0;
}
// 判断是否是运算符
int IsOperator(char ch) {                    
	if (ch == '>' || ch == '<' || ch == '=' || ch == '*' || ch == '-' || ch == '+' || ch == '#')
		return 1;
	else
		return 0;
}
// 判断是否是数字
int IsDigit(char ch) {               
	if ((ch >= '0' && ch <= '9'))
		return 1;
	else
		return 0;
}
// 判断是是否界符
int IsBoundary(char ch) {          
	if (ch == ';' || ch == '.' || ch == ',' || ch == '(' || ch == ')')
		return 1;
	else
		return 0;
}
// 判断是否是保留字
int IsReservedWord(char* str) {          
	for (int i = 0; i < 20; i++) 
		if (reservedWord[i].compare(str) == 0) 
			return 1;
	return 0;
}

// 判断字符串是否合法,合法则保存到单词表中
void ProcessString(char ch) {
	// 字符串 或 数字
	if (IsChar(ch) || IsDigit(ch)) { 
		StrConnect(word, ch);
		charIndex++;
		ProcessString(charTable[charIndex]); //处理下一个字符
	}
	// 运算符或界符等,表示当前单词停止
	else if (ch == ' ' || ch == '\n' || ch == '\0' || IsOperator(ch) || IsBoundary(ch)) {
		// 判断为保留字
		if (IsReservedWord(word)) {
			wordTable[wordIndex++] = word; // 保存到单词表 wordTable 中
			word[0] = '\0';	// word变量初始化
		}
		// 否则判断为标识符
		else {
			if (StrLength(word) >= 8) 
				printf("(标识符长度超长,%s,行号:%d)\n", word, lineNumber);
			else 
				wordTable[wordIndex++] = word; 
			word[0] = '\0';
		}
	}
	// 非法字符(串)
	else {
		StrConnect(word, ch);
		printf("(非法字符(串),%s,行号:%d)\n", word, lineNumber);
		charIndex++;
		word[0] = '\0';
	}
}
// 判断数字串是否合法,合法则保存到单词表中
void ProcessNumber(char ch) {
	// 数字
	if (IsDigit(ch)) {
		StrConnect(word, charTable[charIndex]);
		charIndex++;
		ProcessNumber(charTable[charIndex]);
	}
	// 无符号整数
	else if (!IsChar(ch)) {
		if (StrLength(word) >= 6) 
			printf("(无符号整数越界,%s,行号:%d)\n", word, lineNumber);
		else 
			wordTable[wordIndex++] = word; // 保存到单词表 wordTable 中
		word[0] = '\0';
	}
	// 非法字符(串)
	else {
		while (charTable[charIndex] != ' ' && IsBoundary(charTable[charIndex]) != 1 && charTable[charIndex] != '\0') {
			StrConnect(word, charTable[charIndex]);
			charIndex++;
		}
		printf("(非法字符(串),%s,行号:%d)\n", word, lineNumber);
		word[0] = '\0';
	}
}

// 变量名声明判断
int id() {
	// 拷贝当前读取的单词到word变量中
	int i = 0;
	for (i = 0; i < wordTable[wordIndex].length(); i++) 
		word[i] = wordTable[wordIndex][i];
	word[i] = '\0';
	// 判断该单词不是保留字且不为空
	if (!IsReservedWord(word) && word[0] != '.') {
		wordIndex++;
	}
	else PrintError(1);
}
// 子程序
void subroutine() {
	// 当前单词表匹配 const —— 常量定义
	if (!wordTable[wordIndex].compare("const")) {
		wordIndex++;
		constant();
		// 匹配 "," 说明存在多个变量定义 
		while (!wordTable[wordIndex].compare(",")) {
			wordIndex++;
			constant(); // 处理判断下一个常量
		}
		// 匹配 ";" 说明变量声明结束
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			// 匹配换行符,进入下一行的识别
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++; // 函数加一
				annotation();
			}
			subroutine();
		}
		// 否则出错
		else {
			PrintError(0);
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
				annotation();
			}
			subroutine();
		}
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
			annotation();
		}
	}
	// 当前单词表匹配 var
	else if (!wordTable[wordIndex].compare("var")) {
		wordIndex++;
		variable(); // 读下一个单词,变量 语法判断
		// 匹配 "," 说明有多个变量
		while (!wordTable[wordIndex].compare(",")) {
			wordIndex++;
			variable();
		}
		// 匹配 ";" 说明变量声明结束
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			while (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			annotation();
			subroutine();
		}
		// 否则出错
		else {
			PrintError(0);
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
				annotation();
			}
			subroutine();
		}

	}
	// 当前单词表匹配 procedure
	else if (!wordTable[wordIndex].compare("procedure")) {
		wordIndex++;
		id();
		// 匹配 ";" 说明变量声明结束
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			subroutine();
			if (!wordTable[wordIndex].compare(";")) {
				annotation();
				while (!wordTable[wordIndex].compare("\n")) {
					wordIndex++;
					lineNumber++;
					annotation();
				}
				wordIndex++;
			}
			else {
				PrintError(1);

			}
		} 
		// 否则出错
		else {
			PrintError(0);
			subroutine();
		}
		while (!wordTable[wordIndex].compare("procedure")) {
			wordIndex++;
			id();
			if (!wordTable[wordIndex].compare(";")) {
				wordIndex++;
				subroutine();
				if (!wordTable[wordIndex].compare(";")) wordIndex++;
				else  PrintError(1);
			}
			else {
				PrintError(0);
				subroutine();
			}
		}
	}
	// 当前单词表匹配 换行符
	if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}

	sentence(); // 迭代判断
}
// 常量
void constant() {    
	// 标识符处理判断
	identifier();
	// 匹配等号 = 
	if (!wordTable[wordIndex].compare("=")) {
		wordIndex++;
		number(); // 读入下一个数字进行判断
	}
	// 打印错误
	else PrintError(0);
}
// 变量
void variable() {    
	id();
}
// 语句分析
void sentence() {
	// 匹配 if 语句
	if (!wordTable[wordIndex].compare("if")) {
		wordIndex++;
		condition(); // 读下一个单词,条件 语法判断
		// 条件判断后,匹配 then 语句
		if (!wordTable[wordIndex].compare("then")) {
			wordIndex++;
			// 如果换行,行数加一
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence(); // 读下一个单词,语句 语法判断
		}
		// 不匹配,报错
		else {
			PrintError(0);
			sentence();
		}
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
	}
	// 匹配 while 语句
	else if (!wordTable[wordIndex].compare("while")) {
		wordIndex++;
		condition(); // 读下一个单词,条件 语法判断
		// 条件判断后,匹配 do 语句
		if (!wordTable[wordIndex].compare("do")) {
			wordIndex++;
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence(); // 读下一个单词,语句 语法判断
		}
		// 不匹配,报错
		else {
			PrintError(1);
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence();
		}
	}
	// 匹配 call 语句
	else if (!wordTable[wordIndex].compare("call")) {
		wordIndex++;
		id();
	}
	// 匹配 read 语句
	else if (!wordTable[wordIndex].compare("read")) {
		wordIndex++;
		if (!wordTable[wordIndex].compare("(")) {
			wordIndex++;
			id(); 
			// 匹配 "," 说明有多个变量
			while (!wordTable[wordIndex].compare(",")) {
				wordIndex++;
				id();
			}
			// "(" 匹配 ")" ,结束判断
			if (!wordTable[wordIndex].compare(")")) 
				wordIndex++;
			else  
				PrintError(1);
		}
		else if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
		else  PrintError(0);
	}
	// 匹配 write 语句
	else if (!wordTable[wordIndex].compare("write")) {
		wordIndex++;
		if (!wordTable[wordIndex].compare("(")) {
			wordIndex++;
			expression(); // 读下一个单词 表达式语法判断
			// 匹配 "," 说明有多个表达式
			while (!wordTable[wordIndex].compare(",")) {
				wordIndex++;
				expression();
			}
			// "(" 匹配 ")" ,结束判断
			if (!wordTable[wordIndex].compare(")")) 
				wordIndex++;
			else if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			else PrintError(0);
		}
		else {
			PrintError(1);
			expression();
			while (!wordTable[wordIndex].compare(",")) {
				wordIndex++;
				expression();
			}
			if (!wordTable[wordIndex].compare(")")) wordIndex++;
			else if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			else PrintError(0);
		}
	}
	// 匹配 begin 语句
	else if (!wordTable[wordIndex].compare("begin")) {
		wordIndex++;
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
		sentence();  // 读下一个单词 语句语法判断
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			annotation();
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence();
		}
		else {
			PrintError(0);
			sentence();
		}

		while (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			annotation();
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence();
		}
		// 匹配 end 语句,说明语句判断结束
		if (!wordTable[wordIndex].compare("end")) {
			wordIndex++;
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
		} else {
			PrintError(0);
			return;
		}
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
	}
	// 匹配 换行符
	else if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
	// 匹配 注解
	else if (!wordTable[wordIndex].compare("//") || !wordTable[wordIndex].compare("/*")) {
		annotation();
		subroutine();
	}
	else {
		int tt = 0;
		for (tt = 0; tt < wordTable[wordIndex].length(); tt++) word[tt] = wordTable[wordIndex][tt];
		word[tt] = '\0';
		if (!IsReservedWord(word) && word[0] != '.') {
			id();
			if (!wordTable[wordIndex].compare(":=")) wordIndex++;
			expression();
		}
	}
}
// 注释
void annotation() {
	// 匹配 "\n" 行数加一
	if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
	// 匹配 "//" 为单行注解
	if (!wordTable[wordIndex].compare("//")) {
		wordIndex++;
		wordIndex++;
		while (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
		annotation();
	}
	// 匹配 "/*" 为多行注解
	else if (!wordTable[wordIndex].compare("/*")) {
		wordIndex++;
		while (wordTable[wordIndex].compare("*/")) {
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			else {
				wordIndex++;
			}
		}
		wordIndex++;
	}
	// 一直换行则行数一直加1
	while (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
}
// 条件分析
void condition() {        
	expression(); // 先进行 表达式 判断
	if (!wordTable[wordIndex].compare("=") || !wordTable[wordIndex].compare("#") || !wordTable[wordIndex].compare("<") || !wordTable[wordIndex].compare("<=") || !wordTable[wordIndex].compare(">") || !wordTable[wordIndex].compare(">=")) {
		wordIndex++;
		expression();
	}
	else if (!wordTable[wordIndex].compare("odd")) {
		wordIndex++;
		expression();
	}
	else 
		PrintError(0);
}
// 表达式
void expression() {       
	term(); // 先进行 项 判断
	if (!wordTable[wordIndex].compare("+") || !wordTable[wordIndex].compare("-")) {
		wordIndex++;
		term();
		while (!wordTable[wordIndex].compare("+") || !wordTable[wordIndex].compare("-")) {
			wordIndex++;
			term();
		}

	}
}
// 项
void term() {
	factor();// 先进行 因子 判断
	while (!wordTable[wordIndex].compare("*") || !wordTable[wordIndex].compare("/")) {
		wordIndex++;
		factor();
	}
}
// 因子
void factor() {       
	if (!wordTable[wordIndex].compare("(")) {
		wordIndex++;
		expression();
		if (!wordTable[wordIndex].compare(")")) {
			wordIndex++;
		}
		else PrintError(0);
	}
	else if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
	else wordIndex++;
}
// 数字
void number() {
	wordIndex++;
}
// 标识符
void identifier() {
	wordIndex++;
}


int main() {
	// 程序字符串输入
	charTable[0] = '\0';
	scanf("%[^\.]", charTable); // 读取输入流中的字符,直到遇到第一个句点('.')为止
	charTable[StrLength(charTable)] = '.'; // 在程序字符串结尾添加'.'作为标识符

	// 进行词法分析
	LexicalAnalysis();

	// 进行语法分析
	charIndex = 0;
	wordIndex = 0;
	lineNumber = 1;
	GrammaticalAnalysis();

	return 0;
}

        运行结果如下:

5、扩展

        添加文件输入的功能,程序能够读取指定目录下的源程序字符串txt文件,进行语法分析并将结果输出到指定的文件下。代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include <iostream>
#include <sstream>
using namespace std;

/* ------------ 全局变量声明定义 ------------ */
int lineNumber = 1; // 当前行号

char charTable[2000];				// 字符表 —— 存储输入程序的 所有字符,包括空格、换行等
string wordTable[200] = { "\0" };	// 单词表 —— 存储输入程序的 所有单词,包括换行
char word[88] = "\0";				// 存储单个字符,添加到 wordTable 中

string ENDsign = "end.";	// 结束标识符
int charIndex = 0;			// 记录当前 charTable 字符个数
int wordIndex = 0;			// 记录当前 wordTable 单词个数

char errorMsg[2000] = "";	// 语法错误输出串,用于文件写入
int errorNum = 0;			// 语法错误个数
int errorLine = 0;			// 语法错误行

string reservedWord[20] = { // 保留字
	"begin","call", "const","do","end","if",
	"odd","procedure", "read","then",
	"var","while","write"
};


/* ------------ 函数声明 ------------ */
void LexicalAnalysis();			// 词法分析
void GrammaticalAnalysis();		// 语法分析
void OutputError(int type);		//语法错误输出
int ReadFile(char* path);		// 读取文件
int WriteFile(char* path);		// 写入文件
char* GenerateMessage(int lineNumber);// 生成语法错误字符串

void StrConnect(char* str, char ch);	// 拼接字符串
int StrLength(char* str);				// 计算字符串长度

int IsChar(char ch);			// 判断是否是字符
int IsOperator(char ch);		// 判断是否是运算符
int IsDigit(char ch);			// 判断是否是数字
int IsBoundary(char ch);		// 判断是是否界符
int IsReservedWord(char* str);	// 判断是否是保留字

void ProcessString(char ch);	// 判断字符串是否合法,合法则保存到单词表中
void ProcessNumber(char ch);	// 判断数字串是否合法,合法则保存到单词表中


int id();					// 变量名声明判断
void subroutine();			// 子程序
void constant();			// 常量定义
void variable();			// 变量定义
void sentence();			// 语句分析
void annotation();			// 注释
void condition();			// 条件分析
void expression();			// 表达式
void term();				// 项
void factor();				// 因子
void identifier();			// 标识符
void number();				// 数字


/* ------------ 函数定义 ------------ */
// 词法分析
void LexicalAnalysis() {
	while (charTable[charIndex] != '\0') { // 当前字符表未识别到结束符 '\0'
		if (charTable[charIndex] == '\0')
			break;
		if (charTable[charIndex] == ' ') {
			charIndex++;
			continue;
		}
		if (charTable[charIndex] == '\n') {
			wordTable[wordIndex++] = "\n";  // 将 换行符 保存到单词表 wordTable 中
			charIndex++;
			lineNumber++;	// 程序换行,行数加一
		}
		// 识别到字符
		else if (IsChar(charTable[charIndex])) {
			ProcessString(charTable[charIndex]); // 处理该字符之后的字符串
			continue;
		}
		// 识别到数字
		else if (IsDigit(charTable[charIndex])) {
			ProcessNumber(charTable[charIndex]); // 处理该数字之后的数字串
			continue;
		}
		// 识别到'/' 符
		else if (charTable[charIndex] == '/') {
			// 之后是 '/' ,说明是注释 //
			if (charTable[charIndex + 1] == '/') {
				wordTable[wordIndex++] = "//";
				charIndex = charIndex + 2;
				word[0] = '\0';

				while (charTable[charIndex] != '\n') // 将未换行的字符全部识别为注释
					StrConnect(word, charTable[charIndex++]);
				wordTable[wordIndex++] = word;
				wordTable[wordIndex++] = "\n";
				charIndex++;
				continue;
			}
			// 之后是 '*' ,说明是注释 /*
			else if (charTable[charIndex + 1] == '*') {
				wordTable[wordIndex++] = "/*";
				charIndex = charIndex + 2;
				while (!(charTable[charIndex] == '*' && charTable[charIndex + 1] == '/')) {
					if (charTable[charIndex] == '\n') {
						wordTable[wordIndex++] = "\n";
						charIndex++;
						continue;
					}
					word[0] = '\0';
					while (charTable[charIndex] != '\n') StrConnect(word, charTable[charIndex++]);
					wordTable[wordIndex++] = word;
					wordTable[wordIndex++] = "\n";
					charIndex++;
				}
				wordTable[wordIndex++] = "*/";
				charIndex = charIndex + 2;
				word[0] = '\0';
				continue;
			}
			// 是非法字符(串)
			else {
				while (charTable[charIndex] != ' ' && IsBoundary(charTable[charIndex]) != 1 && charTable[charIndex] != '\0') {
					StrConnect(word, charTable[charIndex]);
					charIndex++;
				}
				printf("(非法字符(串),%s,行号:%d)\n", word, lineNumber);
				word[0] = '\0';
				break;
			}
		}
		// 识别到比较符
		else if (charTable[charIndex] == '<' || charTable[charIndex] == '>') {
			charIndex++;
			// 是 <= 或者 >= 符
			if (charTable[charIndex] == '=') {
				if (charTable[charIndex - 1] == '<')
					wordTable[wordIndex] = "<="; // 保存单词表
				else
					wordTable[wordIndex] = ">="; // 保存单词表
				wordIndex++;
				charIndex++;
				continue;
			}
			// 是 < 或者 > 符
			else {
				if (charTable[charIndex - 1] == '<')
					wordTable[wordIndex] = "<"; // 保存单词表
				else
					wordTable[wordIndex] = ">"; // 保存单词表
				wordIndex++;
				continue;
			}
		}
		// 识别到':'
		else if (charTable[charIndex] == ':') {
			charIndex++;
			if (charTable[charIndex] == '=') {
				wordTable[wordIndex++] = ":="; // 保存单词表
				charIndex++;
				continue;
			}
			else {
				printf(":后面不是=号\n");
				continue;
			}
		}
		// 识别到运算符
		else if (IsOperator(charTable[charIndex])) {
			wordTable[wordIndex++] = charTable[charIndex]; // 保存单词表
			charIndex++;
			continue;
		}
		// 识别到界符
		else if (IsBoundary(charTable[charIndex])) {
			wordTable[wordIndex++] = charTable[charIndex]; // 保存单词表
			charIndex++;
			continue;
		}
		// 识别到非法字符(串)
		else {
			printf("(非法字符(串),%c,行号:%d)\n", charTable[charIndex], lineNumber);
			charIndex++;
		}
	}
}
// 语法分析
void GrammaticalAnalysis() {
	subroutine();
	if (!wordTable[wordIndex].compare(".")) {
		if (errorNum == 0) {
			printf("语法正确\n");
			strcat(errorMsg, "语法正确\n");
		}
			

	}
	else {
		OutputError(0); // 输出语法错误以及行号
		return;
	}
}
// 输出语法错误
void OutputError(int type) {
	if (type == 1) {
		if (errorLine != lineNumber) {
			errorLine = lineNumber;
			printf("(语法错误,行号:%d)\n", lineNumber);
			strcat(errorMsg, GenerateMessage(lineNumber));
			errorNum++;
		}
	}
	else {
		while (wordTable[wordIndex].compare("\n") != 0) 
			wordIndex++;
		if (errorLine != lineNumber) {
			errorLine = lineNumber;
			printf("(语法错误,行号:%d)\n", lineNumber);
			strcat(errorMsg, GenerateMessage(lineNumber));
			errorNum++;
		}
	}
}
// 读取文件
int ReadFile(char* path) {
	FILE* file;
	file = fopen(path, "r");
	if (file == NULL) {
		printf("file is error.");
		return -1;
	}
	int len;
	for (len = 0; len < 2048; len++) {
		fscanf(file, "%c", &charTable[len]);
		if (charTable[len] == '.') {
			len++;
			break;
		}
	}
	charTable[len] = '\0';
	fclose(file);
	return len;
}
// 写入文件
int WriteFile(char* path) {
	FILE* file = NULL;
	file = fopen(path, "w+");
	if (file == NULL) {
		printf("file is error.");
		return -1;
	}
	fputs(errorMsg, file);
	fclose(file);
	return 1;
}
// 生成语法错误字符串
char* GenerateMessage(int lineNumber) {
	char msg[24] = "(语法错误,行号:";
	char endMsg[5] = ")\n";
	char num[5];
	_itoa_s(lineNumber, num, 10);
	strcat(msg, num);
	strcat(msg, endMsg);
	return msg;
}

// 拼接字符串
void StrConnect(char* str, char ch) {        
	int i = 0;
	while (str[i] != '\0') i++;
	str[i] = ch;
	str[i + 1] = '\0';
}
// 计算字符串长度
int StrLength(char* str) {     
	int i = 0;
	while (str[i] != '\0') 
		i++;
	return i;
}

// 判断是否是字符
int IsChar(char ch) {
	if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
		return 1;
	else
		return 0;
}
// 判断是否是运算符
int IsOperator(char ch) {                    
	if (ch == '>' || ch == '<' || ch == '=' || ch == '*' || ch == '-' || ch == '+' || ch == '#')
		return 1;
	else
		return 0;
}
// 判断是否是数字
int IsDigit(char ch) {               
	if ((ch >= '0' && ch <= '9'))
		return 1;
	else
		return 0;
}
// 判断是是否界符
int IsBoundary(char ch) {          
	if (ch == ';' || ch == '.' || ch == ',' || ch == '(' || ch == ')')
		return 1;
	else
		return 0;
}
// 判断是否是保留字
int IsReservedWord(char* str) {          
	for (int i = 0; i < 20; i++) 
		if (reservedWord[i].compare(str) == 0) 
			return 1;
	return 0;
}

// 判断字符串是否合法,合法则保存到单词表中
void ProcessString(char ch) {
	// 字符串 或 数字
	if (IsChar(ch) || IsDigit(ch)) { 
		StrConnect(word, ch);
		charIndex++;
		ProcessString(charTable[charIndex]); //处理下一个字符
	}
	// 运算符或界符等,表示当前单词停止
	else if (ch == ' ' || ch == '\n' || ch == '\0' || IsOperator(ch) || IsBoundary(ch)) {
		// 判断为保留字
		if (IsReservedWord(word)) {
			wordTable[wordIndex++] = word; // 保存到单词表 wordTable 中
			word[0] = '\0';	// word变量初始化
		}
		// 否则判断为标识符
		else {
			if (StrLength(word) >= 8) 
				printf("(标识符长度超长,%s,行号:%d)\n", word, lineNumber);
			else 
				wordTable[wordIndex++] = word; 
			word[0] = '\0';
		}
	}
	// 非法字符(串)
	else {
		StrConnect(word, ch);
		printf("(非法字符(串),%s,行号:%d)\n", word, lineNumber);
		charIndex++;
		word[0] = '\0';
	}
}
// 判断数字串是否合法,合法则保存到单词表中
void ProcessNumber(char ch) {
	// 数字
	if (IsDigit(ch)) {
		StrConnect(word, charTable[charIndex]);
		charIndex++;
		ProcessNumber(charTable[charIndex]);
	}
	// 无符号整数
	else if (!IsChar(ch)) {
		if (StrLength(word) >= 6) 
			printf("(无符号整数越界,%s,行号:%d)\n", word, lineNumber);
		else 
			wordTable[wordIndex++] = word; // 保存到单词表 wordTable 中
		word[0] = '\0';
	}
	// 非法字符(串)
	else {
		while (charTable[charIndex] != ' ' && IsBoundary(charTable[charIndex]) != 1 && charTable[charIndex] != '\0') {
			StrConnect(word, charTable[charIndex]);
			charIndex++;
		}
		printf("(非法字符(串),%s,行号:%d)\n", word, lineNumber);
		word[0] = '\0';
	}
}

// 变量名声明判断
int id() {
	// 拷贝当前读取的单词到word变量中
	int i = 0;
	for (i = 0; i < wordTable[wordIndex].length(); i++) 
		word[i] = wordTable[wordIndex][i];
	word[i] = '\0';
	// 判断该单词不是保留字且不为空
	if (!IsReservedWord(word) && word[0] != '.') {
		wordIndex++;
	}
	else OutputError(1);
}
// 子程序
void subroutine() {
	// 当前单词表匹配 const —— 常量定义
	if (!wordTable[wordIndex].compare("const")) {
		wordIndex++;
		constant();
		// 匹配 "," 说明存在多个变量定义 
		while (!wordTable[wordIndex].compare(",")) {
			wordIndex++;
			constant(); // 处理判断下一个常量
		}
		// 匹配 ";" 说明变量声明结束
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			// 匹配换行符,进入下一行的识别
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++; // 函数加一
				annotation();
			}
			subroutine();
		}
		// 否则出错
		else {
			OutputError(0);
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
				annotation();
			}
			subroutine();
		}
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
			annotation();
		}
	}
	// 当前单词表匹配 var
	else if (!wordTable[wordIndex].compare("var")) {
		wordIndex++;
		variable(); // 读下一个单词,变量 语法判断
		// 匹配 "," 说明有多个变量
		while (!wordTable[wordIndex].compare(",")) {
			wordIndex++;
			variable();
		}
		// 匹配 ";" 说明变量声明结束
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			while (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			annotation();
			subroutine();
		}
		// 否则出错
		else {
			OutputError(0);
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
				annotation();
			}
			subroutine();
		}

	}
	// 当前单词表匹配 procedure
	else if (!wordTable[wordIndex].compare("procedure")) {
		wordIndex++;
		id();
		// 匹配 ";" 说明变量声明结束
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			subroutine();
			if (!wordTable[wordIndex].compare(";")) {
				annotation();
				while (!wordTable[wordIndex].compare("\n")) {
					wordIndex++;
					lineNumber++;
					annotation();
				}
				wordIndex++;
			}
			else {
				OutputError(1);

			}
		} 
		// 否则出错
		else {
			OutputError(0);
			subroutine();
		}
		while (!wordTable[wordIndex].compare("procedure")) {
			wordIndex++;
			id();
			if (!wordTable[wordIndex].compare(";")) {
				wordIndex++;
				subroutine();
				if (!wordTable[wordIndex].compare(";")) wordIndex++;
				else  OutputError(1);
			}
			else {
				OutputError(0);
				subroutine();
			}
		}
	}
	// 当前单词表匹配 换行符
	if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}

	sentence(); // 迭代判断
}
// 常量
void constant() {    
	// 标识符处理判断
	identifier();
	// 匹配等号 = 
	if (!wordTable[wordIndex].compare("=")) {
		wordIndex++;
		number(); // 读入下一个数字进行判断
	}
	// 打印错误
	else OutputError(0);
}
// 变量
void variable() {    
	id();
}
// 语句分析
void sentence() {
	// 匹配 if 语句
	if (!wordTable[wordIndex].compare("if")) {
		wordIndex++;
		condition(); // 读下一个单词,条件 语法判断
		// 条件判断后,匹配 then 语句
		if (!wordTable[wordIndex].compare("then")) {
			wordIndex++;
			// 如果换行,行数加一
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence(); // 读下一个单词,语句 语法判断
		}
		// 不匹配,报错
		else {
			OutputError(0);
			sentence();
		}
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
	}
	// 匹配 while 语句
	else if (!wordTable[wordIndex].compare("while")) {
		wordIndex++;
		condition(); // 读下一个单词,条件 语法判断
		// 条件判断后,匹配 do 语句
		if (!wordTable[wordIndex].compare("do")) {
			wordIndex++;
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence(); // 读下一个单词,语句 语法判断
		}
		// 不匹配,报错
		else {
			OutputError(1);
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence();
		}
	}
	// 匹配 call 语句
	else if (!wordTable[wordIndex].compare("call")) {
		wordIndex++;
		id();
	}
	// 匹配 read 语句
	else if (!wordTable[wordIndex].compare("read")) {
		wordIndex++;
		if (!wordTable[wordIndex].compare("(")) {
			wordIndex++;
			id(); 
			// 匹配 "," 说明有多个变量
			while (!wordTable[wordIndex].compare(",")) {
				wordIndex++;
				id();
			}
			// "(" 匹配 ")" ,结束判断
			if (!wordTable[wordIndex].compare(")")) 
				wordIndex++;
			else  
				OutputError(1);
		}
		else if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
		else  OutputError(0);
	}
	// 匹配 write 语句
	else if (!wordTable[wordIndex].compare("write")) {
		wordIndex++;
		if (!wordTable[wordIndex].compare("(")) {
			wordIndex++;
			expression(); // 读下一个单词 表达式语法判断
			// 匹配 "," 说明有多个表达式
			while (!wordTable[wordIndex].compare(",")) {
				wordIndex++;
				expression();
			}
			// "(" 匹配 ")" ,结束判断
			if (!wordTable[wordIndex].compare(")")) 
				wordIndex++;
			else if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			else OutputError(0);
		}
		else {
			OutputError(1);
			expression();
			while (!wordTable[wordIndex].compare(",")) {
				wordIndex++;
				expression();
			}
			if (!wordTable[wordIndex].compare(")")) wordIndex++;
			else if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			else OutputError(0);
		}
	}
	// 匹配 begin 语句
	else if (!wordTable[wordIndex].compare("begin")) {
		wordIndex++;
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
		sentence();  // 读下一个单词 语句语法判断
		if (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			annotation();
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence();
		}
		else {
			OutputError(0);
			sentence();
		}

		while (!wordTable[wordIndex].compare(";")) {
			wordIndex++;
			annotation();
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			sentence();
		}
		// 匹配 end 语句,说明语句判断结束
		if (!wordTable[wordIndex].compare("end")) {
			wordIndex++;
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
		} else {
			OutputError(0);
			return;
		}
		if (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
	}
	// 匹配 换行符
	else if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
	// 匹配 注解
	else if (!wordTable[wordIndex].compare("//") || !wordTable[wordIndex].compare("/*")) {
		annotation();
		subroutine();
	}
	else {
		int tt = 0;
		for (tt = 0; tt < wordTable[wordIndex].length(); tt++) word[tt] = wordTable[wordIndex][tt];
		word[tt] = '\0';
		if (!IsReservedWord(word) && word[0] != '.') {
			id();
			if (!wordTable[wordIndex].compare(":=")) wordIndex++;
			expression();
		}
	}
}
// 注释
void annotation() {
	// 匹配 "\n" 行数加一
	if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
	// 匹配 "//" 为单行注解
	if (!wordTable[wordIndex].compare("//")) {
		wordIndex++;
		wordIndex++;
		while (!wordTable[wordIndex].compare("\n")) {
			wordIndex++;
			lineNumber++;
		}
		annotation();
	}
	// 匹配 "/*" 为多行注解
	else if (!wordTable[wordIndex].compare("/*")) {
		wordIndex++;
		while (wordTable[wordIndex].compare("*/")) {
			if (!wordTable[wordIndex].compare("\n")) {
				wordIndex++;
				lineNumber++;
			}
			else {
				wordIndex++;
			}
		}
		wordIndex++;
	}
	// 一直换行则行数一直加1
	while (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
}
// 条件分析
void condition() {        
	expression(); // 先进行 表达式 判断
	if (!wordTable[wordIndex].compare("=") || !wordTable[wordIndex].compare("#") || !wordTable[wordIndex].compare("<") || !wordTable[wordIndex].compare("<=") || !wordTable[wordIndex].compare(">") || !wordTable[wordIndex].compare(">=")) {
		wordIndex++;
		expression();
	}
	else if (!wordTable[wordIndex].compare("odd")) {
		wordIndex++;
		expression();
	}
	else 
		OutputError(0);
}
// 表达式
void expression() {       
	term(); // 先进行 项 判断
	if (!wordTable[wordIndex].compare("+") || !wordTable[wordIndex].compare("-")) {
		wordIndex++;
		term();
		while (!wordTable[wordIndex].compare("+") || !wordTable[wordIndex].compare("-")) {
			wordIndex++;
			term();
		}

	}
}
// 项
void term() {
	factor();// 先进行 因子 判断
	while (!wordTable[wordIndex].compare("*") || !wordTable[wordIndex].compare("/")) {
		wordIndex++;
		factor();
	}
}
// 因子
void factor() {       
	if (!wordTable[wordIndex].compare("(")) {
		wordIndex++;
		expression();
		if (!wordTable[wordIndex].compare(")")) {
			wordIndex++;
		}
		else OutputError(0);
	}
	else if (!wordTable[wordIndex].compare("\n")) {
		wordIndex++;
		lineNumber++;
	}
	else wordIndex++;
}
// 数字
void number() {
	wordIndex++;
}
// 标识符
void identifier() {
	wordIndex++;
}



int main() {
	// 程序字符串输入
	char readPath[200];
	char writePath[200];
	printf("输入源程序路径:");
	scanf("%s", readPath);
	printf("输入语法输出文件路径:");
	scanf("%s", writePath);

	if (ReadFile(readPath) != -1) {
		// 进行词法分析
		LexicalAnalysis();

		// 进行语法分析
		charIndex = 0;
		wordIndex = 0;
		lineNumber = 1;
		GrammaticalAnalysis();

		WriteFile(writePath);
	}
	return 0;
}

        指定的文件如下:

         运行结果如下:

       读取源程序文件:

         写入结果文件:

猜你喜欢

转载自blog.csdn.net/sun80760/article/details/131085023