编译原理 设计报告(附源码)

本文详细介绍了编译原理中的词法分析和语法分析过程。首先,使用DFA和NFA构造词法分析器,处理常规单词,识别关键词、标识符、常量等。然后,通过LL(1)或LR(1)方法创建语法分析器,处理2型文法,判断源代码是否符合文法规则。文中提供了相应的代码实现和例子,展示了编译器的关键组件和工作流程。

编译原理 设计报告

任务 1:创建一个词法分析程序,该程序支持分析常规单词。
必须使用 DFA(确定性有限自动机)或 NFA(不确定性有限自动机)来实现此程序。 程序
有两个输入:一个文本文档,包括一组 3º型文法(正规文法);一个源代码文本文档,包含
一组需要识别的字符串(程序代码)。 程序的输出是一个 token(令牌)表,该表由 5 种 token
组成:关键词,标识符,常量,界符和运算符。
词法分析程序的推荐处理逻辑:根据用户输入的正规文法,生成 NFA,再确定化生成 DFA,
根据 DFA 编写识别 token 的程序,从头到尾从左至右识别用户输入的源代码,生成 token 列
表(三元组:所在行号,类别,token 内容)
要求:词法分析程序可以准确识别:科学计数法形式的常量(如 0.314E+1),复数常量(如
10+12i),可检查整数常量的合法性,标识符的合法性(首字符不能为数字等),尽量符合真
实常用高级语言要求的规则。
任务 2:创建一个使用 LL(1) 方法或 LR(1) 方法的语法分析程序。
程序有两个输入:1)一个是文本文档,包含 2º型文法(上下文无关文法);2)任务 1 词法
分析程序输出的(生成的)token 令牌表。程序的输出包括:YES 或 NO(源代码字符串符合
此 2º型文法,或者源代码字符串不符合此 2º型文法);错误提示文件,如果有语法错标示出
错行号,并给出大致的出错原因。
语法分析程序的推荐处理逻辑:根据用户输入的 2º型文法,生成 Action 及 Goto 表,设计合
适的数据结构,判断 token 序列(用户输入的源程序转换)。建议能演示语法处理的中间过
程。
提示:选用 LR(1)方法的起评分数高

一、词法分析器实现

这部分我实现的是类似于c语言的三型文法,可能有点长所以就放了一点

start>0~numbertail
start>1~numbertail
start>2~numbertail
start>3~numbertail
start>4~numbertail
start>5~numbertail

接下来就是对上述的文法进行分析

单词类型以及token类型的实现

enum wordType {
	VARIABLE,
	KEYWORD,
	LIMIT,
	OPERATION,
	CONST
};

class token {
public:
	int lineNumber; 	// 标识当前token字符所在的行号
	wordType type;		// 标识当前token字符的类型
	string value;		// token的实际值
	token(int lineNumber, wordType type, string value):\
		lineNumber(lineNumber), type(type),value(value){}
	token() {
		lineNumber = 0;
		type = VARIABLE;
	}
};

nfa节点的构造

要使用自动机就要先构建nfa

class nfaNode
{
public:
	bool isStart;							// 判断是不是起点
	bool isEnd;								// 判断是不是终点
	string nodeName;						// 节点的名字
	map<string, string> nextnode;			// 节点通往下一个节点的路径<边名,下个节点名>
	nfaNode() {
		isStart = false;
		isEnd = false;
	};
	nfaNode(bool isStart, bool isEnd, string nodeName) :\
		isStart(isStart),isEnd(isEnd), nodeName(nodeName) {}
	bool addEdge(string, string nextNode);	// 用于添加一条边
};
// nfa节点集合
class nfaSet  
{
public:
	nfaNode *endNode=new nfaNode(false,true,"end");     // 将end节点加入集合
	map<string, nfaNode*> nodePool;						// 表示所有的节点<节点名字,nfa指针>
	nfaSet() {
		nodePool.insert(make_pair("end", endNode));		// 将end节点先加入到集合中
	}
	void readGrammer(string filename);					// 读取文法
};

dfa节点的构造

nfa构造完啦,该把他确定话了

class dfaNode {
public:
	bool isStart;			// 用于判断是否是起始节点
	bool isEnd;				// 用于判断是否是终结节点
	int index;				// 用于标识当前节点序号
	set<string> nfaNodeSet;			// 当前dfa节点中包含的nfa节点
	map<string, int> nextnode;		// 当前dfa节点状态转移方式<转移字符,转移到的状态>
	dfaNode(bool isStart,bool isEnd,int index):\
		isStart(isStart),isEnd(isEnd),index(index){}
	bool addEdge(string ch, int nextIndex);    // 构建一条从当前节点指向下一节点的又向边
};
// dfa节点集合
class dfaSet {
private:
	map<int, dfaNode*> dfaPool;			// 集合中的所有点
	nfaSet nfa;							// 之前构造好的nfa放进来
	int numberOfNode = 0;				// 见名知意,不解释了
	vector<token*> tokens;				// 得到的token序列
public:
	void nfa_to_dfa();									// 把nfa确定化
	bool is_new_set(set<string> testSet);				// 检查集合是否已经存在
	bool is_start_in(set<string> testSet);				// 检查开始节点是不是在这个dfa节点中
	bool is_end_in(set<string> testSet);				// 同上
	dfaNode* getNode_BynfaSet(set<string> nfaNames);	// 见名知意,不解释了
	void readProgram(string programfile);				// 读取程序
	bool is_end_index(int index);						// 判断当前所处状态是不是终态
	bool canAccept(int &curr_index, string ch);			// 判断输入字符对于当前状态是不是可以接收,可以接受的话会自动														// 改变当前状态
	void writeTokenFile(string filename);				// 读入程序文件,输出token文件
	
    // 依次传入三型文法,程序文档,想要的token文件名,直接完成全部步骤 
	dfaSet(string Grammerfile,string Programfile,string Tokenfile) {	
		nfa = nfaSet();
		nfa.readGrammer(Grammerfile);
		nfa_to_dfa();
		readProgram(Programfile);
		writeTokenFile(Tokenfile);
	}
};

到这里词法分析就完事了

看下结果

// 读入的程序文档
int okok = 111 ;

func double test (int t ,double yyy ) {
	if ( t ) {
		while (yyy ) {
			111 ;
		}
	}
}

func int main ( ) {
	int a = 100 ;
	double b = 13.95 ;
	float c = 0.55E+233 ;
	complex d = 6+3i ;
	
	test (a, b ) ;

	c = b - a ;
	return 0 ;
}

部分token

1	KEYWORD	int
1	VARIABLE	okok
1	OPERATION	=
1	CONST	111
1	LIMIT	;
3	KEYWORD	func
3	KEYWORD	double
3	VARIABLE	test
3	LIMIT	(
3	KEYWORD	int
3	VARIABLE	t
3	LIMIT	,
3	KEYWORD	double
3	VARIABLE	yyy
3	LIMIT	)
3	LIMIT	{
4	KEYWORD	if
4	LIMIT	(
4	VARIABLE	t
4	LIMIT	)
4	LIMIT	{
/////////////////////////////////////////////////////////////////////////
////////					词法分析完成					/////////////////
/////////////////////////////////////////////////////////////////////////

二、语法分析器实现

这里比前面稍微麻烦些,准备的东西有点多,下面是我写的二型文法

// ssstart 是对文法的拓广
ssstart>sstart
sstart>start
start>defineVar~start
start>defineFunc~start
start>$
// datatype 数据类型
datatype>int
datatype>double
datatype>long
datatype>float
datatype>void
datatype>string
datatype>bool
datatype>complex
// varName 变量名称
// expression 基本表达式(可以使函数调用,变量引用,或者常值使用)
expression>const
expression>variable
expression>funcName~(~list~)
list>list~varName
list>$
expression>expression~operater~expression
expression>(~expression~)
operater>+
operater>-
operater>*
operater>/
operater>!
operater>|
operater>&
operater>=
operater>%
// varParameter 变量属性
// varParameter~optionalSwitch 变量定义的可选操作(同时定义多个量)
// varValue 变量的值
// 变量定义
defineVar>datatype~variable~=~expression~;
// parameterList函数参数列表
// paramterValue参数
// funcName 函数名
// funcBody 函数体
// paraName 参数名称
// 函数定义
defineFunc>func~datatype~funcName~(~parameterList~)~{~funcBody~}
funcName>variable
funcName>main
parameterList>$
parameterList>datatype~variable~parameterList
parameterList>,~datatype~variable
funcBody>defineVar~funcBody
funcBody>assignment~funcBody
funcBody>judgment~funcBody
funcBody>loop~funcBody
funcBody>expression~;~funcBody
funcBody>return~expression~;
funcBody>$
// 赋值语句
varName>variable
assignment>varName~=~expression~;
// judgeBody 判断成立后的语句
// 条件判断语句
judgeBody>$
judgment>if~(~expression~)~{~judgeBody~}
judgeBody>defineVar~judgeBody
judgeBody>assignment~judgeBody
judgeBody>judgment~judgeBody
judgeBody>loop~judgeBody
judgeBody>expression~;~judgeBody
judgeBody>return~expression~;
// loopBody 循环体语句
// 循环语句
loop>while~(~expression~)~{~loopBody~}
loopBody>defineVar~loopBody
loopBody>assignment~loopBody
loopBody>judgment~loopBody
loopBody>loop~loopBody
loopBody>expression~;~loopBody
loopBody>return~expression~;
loopBody>$

产生式构造

// 表示一条产生式
class product {
public:
	int index;					// 产生式序号
	string left;				// 产生式左端
	list<string> right;			// 产生式右端
	product() { index = 0; }		
	product(int index,string left,list<string> right):\
		index(index),left(left),right(right){}
};

项目构造

// 表示项目
class item {
public:
	string left;					// 产生式左端
	vector<string> rights;			// 产生式右端
	int dotPos;						// 那个小点的位置
	set<string> symbols;			// 向前搜索符
	int productIndex;				// 产生式序号(规约时候用)
	item() {
		left = "";
		dotPos = 0;
		productIndex = 0;
	}
	item(string left,vector<string> right,int pos,int productIndex, set<string> symbols):\
		left(left), rights(right), dotPos(pos), symbols(symbols), productIndex(productIndex) {}
	item(product product) {
		dotPos = 0;
		productIndex = product.index;
		left = product.left;
		for (auto i = product.right.begin(); i != product.right.end(); i++) {
			rights.push_back(*i);
		}
	}
};

项目集构造

// 表示一个项目集
class itemSet{
public:
	int index;					// 项目集序号
	vector<item> items;			// 项目集中的项目
	map<string, int> GOTO;		// 此项目集的状态转移<边名,下个状态序号>
	itemSet(int index, vector<item> items) :index(index), items(items){}
	itemSet() {
		index = 0;
	}
	bool isRepeat(item temp);
	itemSet getNextNode(string str);	// 根据str的值创建一个项目集,并且用str表示这两个点的边名
};

分析器构造

class LRanalsys {
private:
	set<string> NonTerminal, Terminal, allSymbol;		// 终结符,非终结符,和所有符号
	map<int, product*> products;						// 所有产生式
	map<string,vector<int>> sameLeftProduct;			// 左部相同的所有产生式
	int numberOfItemSet;								// 见名知意
	map<int, itemSet> itemSets;							// 所有项目集<项目集序号,项目集对象>
	map<string, set<string>> firstSet;					// 所有符号的FIRST集
	vector<int> statusStack;							// 状态栈
	vector<string> symbolsStack;						// 符号栈
	vector<token> tokens;								// 读入的token序列
	vector<map<string, pair<char, int>>> ACTION;		// action表和goto表
	vector<map<string, int>> GOTO;

	product* getProduct(int index);						// 根据序号获取产生式
	void readGrammer(string filename);					// 读入文法
	void getTerminal();									// 获取所有终结符
	bool canInferNull(string str);						// 看看str对应的非终结符能不能推出空
	bool isTerminal(string str);						// 看看是不是终结符
	bool isNonTerminal(string str);						// 同上
	void getsameLeftProduct();							// 见名知意
	void getAllFirst();									// 获取所有first集
	bool isRepeatItemSet(itemSet set,int &repeatPos);	// 看看这个项目集是不是重复的,是的话就把repeatPos置为重复项														// 目集的序号
	void getClosure(itemSet &tempSet);					// 构造输入项目的闭包
	void getSymbols(set<string> &symbols,vector<string> behind, set<string> sym);	// 获取向前搜索符
	bool getNextNode(itemSet &tempSet,string str);		// 构造下个节点
	void getAllItemSets();								// 构造整个项目集转换图
	void creatGOTO_ACTION();							// 构造action和goto(我发现直接用项目集也挺好的,写了这部分														// 但是没用,直接用项目集做了)
	void readToken(string tokenName);					// 读token文件
	void analyseToken();								// 分析token文件
	void printSymbolStack();							// 打印符号栈
	void printStatusStack();							// 打印状态栈
    
	
public:
    // 输入二型文法和token文件,一步到位,直接分完成
	LRanalsys(string grammerName,string tokenName) {
		numberOfItemSet = 0;
		readGrammer(grammerName);
		getTerminal();
		getsameLeftProduct();
		getAllFirst();
		getAllItemSets();
		readToken(tokenName);
		statusStack.push_back(0);
		symbolsStack.push_back("#");
		analyseToken();
	}
};

最后看一下结果

在这里插入图片描述

剩下的语义分析不想写了,给多少分算多少分吧

更新:答辩完了,可以放代码了,代码里有些小bug,请大家自行发现更改

//compiling.h

#include<iostream>
#include<fstream>
#include<map>
#include<set>
#include<vector>
#include<list>
#include<algorithm>
#include<string>
#include<stack>
#include<queue>
#include<ctime>
using namespace std;
set<string> keyWord{ "int","float","short","long","double","bool" ,"void","string","char","complex",\
						"do","while","for","if","else","else if","case","break","continue"\
						"include","define","using","namespace","std","main","iostream","func","return"
};
set<string> limit;
set<string> opera;
set<string> terminal;

enum wordType {
	VARIABLE,
	KEYWORD,
	LIMIT,
	OPERATION,
	CONST
};

static wordType getType(string str);

static bool isKey(string str) {
	for (auto i = keyWord.begin(); i != keyWord.end(); i++) {
		if (str._Equal(*i))
			return true;
	}
	return false;
}

static bool isOper(string str) {
	for (auto i = opera.begin(); i != opera.end(); i++) {
		if (str._Equal(*i))
			return true;
	}
	return false;
}

static bool isLimit(string str) {
	for (auto i = limit.begin(); i != limit.end(); i++) {
		if (str._Equal(*i))
			return true;
	}
	return false;
}

class nfaNode
{
public:
	bool isStart;
	bool isEnd;
	string nodeName;
	map<string, string> nextnode;
	nfaNode() {
		isStart = false;
		isEnd = false;
	};
	nfaNode(bool isStart, bool isEnd, string nodeName) :\
		isStart(isStart),isEnd(isEnd), nodeName(nodeName) {}
	bool addEdge(string, string nextNode);
};

// nfa节点集合
class nfaSet
{
public:
	nfaNode* endNode = new nfaNode(false, true, "end");     // 将end节点加入集合
	map<string, nfaNode*> nodePool;						// 表示所有的节点<节点名字,nfa指针>
	nfaSet() {
		nodePool.insert(make_pair("end", endNode));		// 将end节点先加入到集合中
	}
	void readGrammer(string filename);					// 读取文法
};


class token {
public:
	token(int lineNumber, wordType type, string value):\
		lineNumber(lineNumber), type(type),value(value){}
	token() {
		lineNumber = 0;
		type = VARIABLE;
	}
	int lineNumber;
	wordType type;
	string value;
};

class dfaNode {
public:
	bool isStart;			// 用于判断是否是起始节点
	bool isEnd;				// 用于判断是否是终结节点
	int index;				// 用于标识当前节点序号
	set<string> nfaNodeSet;			// 当前dfa节点中包含的nfa节点
	map<string, int> nextnode;		// 当前dfa节点状态转移方式<转移字符,转移到的状态>
	dfaNode(bool isStart, bool isEnd, int index) :\
		isStart(isStart), isEnd(isEnd), index(index) {}
	bool addEdge(string ch, int nextIndex);    // 构建一条从当前节点指向下一节点的又向边
};

class dfaSet {
private:
	map<int, dfaNode*> dfaPool;
	nfaSet nfa;
	int numberOfNode = 0;
	vector<token*> tokens;
public:
	void nfa_to_dfa();
	bool is_new_set(set<string> testSet);
	bool is_start_in(set<string> testSet);
	bool is_end_in(set<string> testSet);
	dfaNode* getNode_BynfaSet(set<string> nfaNames);
	void readProgram(string programfile);
	bool is_end_index(int index);
	bool canAccept(int &curr_index, string ch);
	void writeTokenFile(string filename= "token.yyy");

	dfaSet(string Grammerfile,string Programfile,string Tokenfile) {
		nfa = nfaSet();
		nfa.readGrammer(Grammerfile);
		nfa_to_dfa();
		readProgram(Programfile);
		writeTokenFile(Tokenfile);
	}
};


/////////////////////////////////////////////////////////////////////////
////////				词法分析完成					/////////////////
/////////////////////////////////////////////////////////////////////////


// 表示一条产生式
class product {
public:
	int index;
	string left;
	list<string> right;
	product() { index = 0; }
	product(int index,string left,list<string> right):\
		index(index),left(left),right(right){}
};

// 表示项目
class item {
public:
	string left;
	vector<string> rights;
	int dotPos;
	set<string> symbols;
	int productIndex;
	item() {
		left = "";
		dotPos = 0;
		productIndex = 0;
	}
	item(string left,vector<string> right,int pos,int productIndex, set<string> symbols):\
		left(left), rights(right), dotPos(pos), symbols(symbols), productIndex(productIndex) {}
	item(product product) {
		dotPos = 0;
		productIndex = product.index;
		left = product.left;
		for (auto i = product.right.begin(); i != product.right.end(); i++) {
			rights.push_back(*i);
		}
	}
};

// 表示一个项目集
class itemSet{
public:
	int index;
	vector<item> items;
	map<string, int> GOTO;
	itemSet(int index, vector<item> items) :index(index), items(items){}
	itemSet() {
		index = 0;
	}
	bool isRepeat(item temp);
	itemSet getNextNode(string str);
};


class LRanalsys {
private:
	set<string> NonTerminal, Terminal, allSymbol;
	map<int, product*> products;
	map<string,vector<int>> sameLeftProduct;
	int numberOfItemSet;
	map<int, itemSet> itemSets;
	map<string, set<string>> firstSet;
	vector<int> statusStack;
	vector<string> symbolsStack;
	vector<token> tokens;
	vector<map<string, pair<char, int>>> ACTION;
	vector<map<string, int>> GOTO;

	product* getProduct(int index);
	void readGrammer(string filename);
	void getTerminal();
	bool canInferNull(string str);
	bool isTerminal(string str);
	bool isNonTerminal(string str);
	void getsameLeftProduct();
	void getAllFirst();
	bool isRepeatItemSet(itemSet set,int &repeatPos);
	void getClosure(itemSet &tempSet);
	void getSymbols(set<string> &symbols,vector<string> behind, set<string> sym);
	bool getNextNode(itemSet &tempSet,string str);
	void getAllItemSets();
	void creatGOTO_ACTION();
	void readToken(string tokenName= "token.yyy");
	void analyseToken();
	void printSymbolStack();
	void printStatusStack();
	
public:
	LRanalsys(string grammerName,string tokenName) {
		numberOfItemSet = 0;
		readGrammer(grammerName);
		getTerminal();
		getsameLeftProduct();
		getAllFirst();
		getAllItemSets();
		readToken(tokenName);
		statusStack.push_back(0);
		symbolsStack.push_back("#");
		analyseToken();
	}
};

#include "compiling.h"

static wordType getType(string str)
{
    while (str[0] == ' ' || str[0] == '\t')
        str.erase(str.begin());
    if (isKey(str)) {
        return KEYWORD;
    }
    else if (isLimit(str)) {
        return LIMIT;
    }
    else if (isOper(str)) {
        return OPERATION;
    }
    else if (str[0] >= '0' && str[0] <= '9') {
        return CONST;
    }
    else {
        return VARIABLE;
    }
}


bool nfaNode::addEdge(string ch, string nextNode)
{
    auto res=nextnode.insert(make_pair(ch, nextNode));
    return true;
}

void nfaSet::readGrammer(string filename)
{
    ifstream file;
    string line;
    nfaNode *newNode1, *newNode2;
    string leftPart, rightPart1, rightPart2;
    file.open(filename, ios::in);
    
    if (!file.is_open()) {
        cout << "error: cannot open aim file" << endl;
        exit(1);
    }

    while (getline(file, line)) {

        if (line.empty())
            continue;

        auto infer = line.find('>');
        if (infer != string::npos) {
            leftPart = line.substr(0, infer);
            // 看看左部有没有,没有就把这个状态加进去
            auto findRes = nodePool.find(leftPart);
            if (findRes == nodePool.end()) {
                if (leftPart._Equal("start")) {
                    newNode1 = new nfaNode(true, false, "start");
                }
                else {
                    newNode1 = new nfaNode(false, false, leftPart);
                }
                nodePool.insert(make_pair(leftPart, newNode1));
            }else {
                newNode1 = findRes->second;
            }
            auto link = line.find('~');
            if (link == string::npos) { // S->a
                rightPart1 = line.substr(infer+1, 1);
                terminal.insert(rightPart1 + "@");
                newNode1->addEdge(rightPart1+"@", "end");
            }else { // S->aA
                rightPart1 = line.substr(infer + 1, 1);
                terminal.insert(rightPart1);
                rightPart2 = line.substr(infer + 3, line.length() - infer - 2);
                if (rightPart2 == "limit") {
                    limit.insert(rightPart1);
                }
                if (rightPart2 == "operater") {
                    opera.insert(rightPart1);
                }
                if (nodePool.find(rightPart2) == nodePool.end()) {
                    // A不在状态集合中,把他添加进去
                    if (rightPart2 == "operater" || rightPart2 == "limit") {
                        newNode2 = new nfaNode(false, true, rightPart2);
                    }else {
                        newNode2 = new nfaNode(false, false, rightPart2);
                    }
                    nodePool.insert(make_pair(rightPart2, newNode2));
                }
                newNode1->addEdge(rightPart1, rightPart2);
            }
        }else {
            cout << "error: input error" << endl;
            exit(1);
        }
    }
 /* for (auto i = nodePool.begin(); i != nodePool.end(); i++) {
        cout << i->first << " edge size:  "<< i->second->nextnode.size() << endl;
    }*/
}


void dfaSet::nfa_to_dfa()
{
    dfaNode* newNode1, * newNode2=nullptr;
    set<string> nodeNameSet;

    newNode1 = new dfaNode(true, false, numberOfNode);
    newNode1->nfaNodeSet.insert("start");
    dfaPool.insert(make_pair(numberOfNode++, newNode1));

    for (auto i = dfaPool.begin(); i != dfaPool.end(); i++) {
        //对于每一个dfa节点都进行遍历
        dfaNode *currNode = i->second;
        for (auto j = terminal.begin(); j != terminal.end(); j++) { 
            //遍历全部的terminal
            set<string> newNodeNames;
            for (auto k = currNode->nfaNodeSet.begin(); k != currNode->nfaNodeSet.end(); k++) {
                // 遍历当前dfa节点中的nfa节点集合
                nfaNode *curr_nfaNode = nfa.nodePool.find(*k)->second;
                string curr_nfaNode_Name = nfa.nodePool.find(*k)->first;
                // 检查这个节点有没有包含此terminal的边
                for (auto l = curr_nfaNode->nextnode.begin(); l != curr_nfaNode->nextnode.end(); l++) {
                    // nfa集合中的这个节点有包含这个terminal的边
                    if (j->_Equal(l->first)||j->_Equal(l->first+"@")) {
                        // 把这条边上的信息保存下来
                        newNodeNames.insert(l->second);
                        int x=0;
                    }
                }
            }
            // 检查新的集合是不是和原有的重合,如果是新的节点集合就把他加到dfaPool中
            if (is_new_set(newNodeNames)) {
                if (newNodeNames.size() == 0) {
                    continue;
                }
                if (is_start_in(newNodeNames)) {
                    newNode2 = new dfaNode(true, false, numberOfNode);
                }else if (is_end_in(newNodeNames)) {
                    newNode2 = new dfaNode(false, true, numberOfNode);
                }else {
                    newNode2 = new dfaNode(false, false, numberOfNode);
                }
                newNode2->nfaNodeSet = newNodeNames;
                dfaPool.insert(make_pair(numberOfNode, newNode2));
                currNode->addEdge(*j, numberOfNode);
                numberOfNode++;
            }else { // 已经有了这个集合,currNode和这个集合建立连接
                dfaNode* tempNode = getNode_BynfaSet(newNodeNames);
                if (tempNode == nullptr) {
                    cout << "error: unknow error" << endl;
                    exit(1);
                }
                currNode->addEdge(*j, tempNode->index);
            }
        }
    }
}

// 检查集合是否已经存在
bool dfaSet::is_new_set(set<string> testSet)
{
    for (auto i = dfaPool.begin(); i != dfaPool.end(); i++) {
        dfaNode* tempNode = i->second;
        if (tempNode->nfaNodeSet == testSet)
            return false;
    }
    return true;
}

bool dfaSet::is_start_in(set<string> testSet)
{
    for (auto i = testSet.begin(); i != testSet.end(); i++) {
        if (i->_Equal("start"))
            return true;
    }
    return false;
}

bool dfaSet::is_end_in(set<string> testSet)
{
    for (auto i = nfa.nodePool.begin(); i != nfa.nodePool.end(); i++) {
        if (i->second->isEnd) {
            for (auto j = testSet.begin(); j != testSet.end(); j++) {
                if (i->first._Equal(*j))
                    return true;
            }
        }
    }
    return false;
}

dfaNode* dfaSet::getNode_BynfaSet(set<string> nfaNames)
{
    for (auto i = dfaPool.begin(); i != dfaPool.end(); i++) {
        dfaNode* tempNode = i->second;
        if (tempNode->nfaNodeSet == nfaNames) {
            return tempNode;
        }
    }
    return nullptr;
}


bool dfaNode::addEdge(string ch, int nextIndex)
{
    nextnode.insert(make_pair(ch, nextIndex));
    return true;
}

void dfaSet::readProgram(string programfile)
{
    ifstream file;
    string line;
    token* newtoken;
    int linenumber = 0;
    file.open(programfile, ios::in);

    if (!file.is_open()) {
        cout << "error: can open progrem" << endl;
        exit(1);
    }

    while (getline(file,line)) {
        linenumber++;
        string tempstr,tostr;
        int curr_index=0;
        // 从左至右依次遍历获取到的一行字符串
        // 当遇到隔断时候停止规约,或者规约到不能接受的字符时候停止
        for (int i = 0; i < line.length(); i++) {
            if (line[i] == ' ' || line[i] == '\t' || i == line.length()-1) {
                // 当后续遇到了隔断或者到了本行末尾
                if (tempstr.empty()) {
                    tostr.push_back(line[i]);
                    if (i == line.length()-1&& tostr != "\t" && tostr != " ") {
                        newtoken = new token(linenumber, getType(tostr), tostr);
                        tokens.push_back(newtoken);
                    }
                    tostr = "";
                }else {
                    newtoken = new token(linenumber, getType(tempstr), tempstr);
                    tokens.push_back(newtoken);
                    tempstr = "";
                    curr_index = 0;
                }
            }else {
                // 没有遇到分隔,可以继续规约,当前状态不能规约时候检查是否是终态,
                // 是的话就加入到token中否则报错
                tostr.push_back(line[i]);
                if (canAccept(curr_index,tostr)){// 可以接受
                    tempstr += tostr;
                }else {// 接受不了
                    if (is_end_index(curr_index)) {// 是终态,创建token
                        newtoken = new token(linenumber, getType(tempstr), tempstr);
                        tokens.push_back(newtoken);
                    }else {// 不是终态,报错
                        cout << "error: " << " 无法识别的字符, 第" << linenumber << "行" << endl;
                    }
                    tempstr = "";
                    tempstr += tostr;
                    curr_index = 0;
                }
                tostr = "";
            }
        }
    }
}

bool dfaSet::is_end_index(int index)
{
    for (auto i = dfaPool.begin(); i != dfaPool.end(); i++) {
        if (index == i->first) {
            if (i->second->isEnd)
                return true;
        }
    }
    return false;
}

bool dfaSet::canAccept(int &curr_index, string ch)
{
    auto temp = dfaPool.find(curr_index)->second;
    for (auto i = temp->nextnode.begin(); i != temp->nextnode.end(); i++) {
        if ((ch + "@")._Equal(i->first)|| (ch)._Equal(i->first)) {
            curr_index = i->second;
            return true;
        }
    }
    return false;
}

void dfaSet::writeTokenFile(string filename)
{
    fstream file;
    file.open(filename,ios::out);

    for (int i = 0;i<tokens.size(); i++) {
        string line, type;
        switch (tokens[i]->type)
        {
        case 0:
            type = "VARIABLE";
            break;
        case 1:
            type = "KEYWORD";
            break;
        case 2:
            type = "LIMIT";
            break;
        case 3:
            type = "OPERATION";
            break;
        case 4:
            type = "CONST";
            break;
        default:
            break;
        }
        line = to_string(tokens[i]->lineNumber) + '\t' + type + '\t' + tokens[i]->value + '\n';
        file << line;
    }
    file.close();
}

void   Delay(int   time)
{
    clock_t   now = clock();
    while (clock() - now < time);
}




/////////////////////////////////////////////////////////////////////////
////////				词法分析完成					/////////////////
/////////////////////////////////////////////////////////////////////////




// 对项目的等于号进行运算符重载
bool operator==(const item& item1, const item& item2) {
    if (item1.left != item2.left)
        return false;
    if (item1.rights.size() != item2.rights.size())
        return false;
    if (item1.dotPos != item2.dotPos)
        return false;
    if (item1.symbols != item2.symbols)
        return false;
    for (int i = 0; i < item1.rights.size(); i++) {
        if (!item1.rights[i] ._Equal( item2.rights[i]))
            return false;
    }
    return true;
}

bool operator<(const item& item1, const item& item2) {
    if (item1.left < item2.left)
        return true;
    return false;
}

// 对项目集的等于号进行运算符重载
bool operator==(const itemSet& itemSet1, const itemSet& itemSet2) {
    if (itemSet1.items.size() != itemSet2.items.size())
        return false;
    for (auto i = itemSet1.items.begin(); i != itemSet1.items.end(); i++) {
        bool flag = false;
        for (auto j = itemSet2.items.begin(); j != itemSet2.items.end(); j++) {
            if (*i == *j)
                flag = true;
        }
        if (flag == false)
            return false;
    }
    return true;
}


void LRanalsys::readGrammer(string filename)
{
    fstream file;
    string line;
    string left, right;
    int numberOfline = 0;
    file.open(filename, ios::in);

    if (!file.is_open()) {
        cout << "error: 无法打开文件" << endl;
        exit(1);
    }
    // 找到产生式中所有的终结符和非终结符
    while (getline(file, line)) {
        product *newProduct;
        list<string> rightList;
        if (line.empty())
            continue;
        if (line[0] == '/') {
            continue;
        }
        auto infer = line.find(">");
        if (infer != string::npos) {
            left = line.substr(0, infer);
            allSymbol.insert(left);
            NonTerminal.insert(left);
            line.erase(0, infer + 1);
            auto tempPos = line.find("~");
            while (tempPos != string::npos) {
                right = line.substr(0, tempPos);
                rightList.push_back(right);
                allSymbol.insert(right);
                line.erase(0, tempPos + 1);
                tempPos = line.find("~");
            }
            if (!line.empty()) {
                allSymbol.insert(line);
                rightList.push_back(line);
            }
            newProduct =new product(numberOfline++, left, rightList);
            products.insert(make_pair(numberOfline - 1, newProduct));
        }
        else {
            cout << "error: 文件格式错误" << endl;
            exit(1);
        }
    }
}


void LRanalsys::getTerminal()
{
    for (auto i = allSymbol.begin(); i != allSymbol.end(); i++) {
        bool flag = false;
        for (auto j = NonTerminal.begin(); j != NonTerminal.end(); j++) {
            if (i->_Equal(*j)) {
                flag = true;
                break;
            }
        }
        if (flag)
            continue;
        Terminal.insert(*i);
    }
}

void LRanalsys::getsameLeftProduct()
{
    for (auto i = NonTerminal.begin(); i != NonTerminal.end(); i++) {
        vector<int> indexList;
        int count = 0;
        for (auto j = products.begin(); j != products.end(); j++) {
            product* temp = j->second;
            if (i->_Equal(temp->left)) {
                indexList.push_back(temp->index);
            }
        }
        sameLeftProduct.insert(make_pair(*i, indexList));
    }
}

bool LRanalsys::canInferNull(string str)
{
    auto temp = sameLeftProduct.find(str)->second;
    for (int i = 0; i < temp.size(); i++) {
        auto product = getProduct(i);
        if (product->right.front()._Equal("$"))
            return true;
    }
    return false;
}


void LRanalsys::getAllFirst()
{
    // 初始化非终结符first集
    for (auto i = NonTerminal.begin(); i != NonTerminal.end(); i++) {
        set<string> str;
        firstSet.insert(make_pair(*i, str));
    }
    // 初始化终结符first集
    for (auto i = Terminal.begin(); i != Terminal.end(); i++) {
        set<string> str{ *i };
        firstSet.insert(make_pair(*i, str));
    }
    size_t pre_size = -1, now_size = 0;
    while (pre_size != now_size) {
        pre_size = now_size;
        for (int i = 0; i < products.size(); i++) {
            auto tempProduct = *products[i];
            // 产生式右边第一个字符是终结符
            if (isTerminal(tempProduct.right.front())) {
                firstSet[tempProduct.left].insert(tempProduct.right.front());
            }
            else {
                bool notNULL = false;
                for (auto j = tempProduct.right.begin(); j!=tempProduct.right.end();j++) {
                    if (isTerminal(*j)) {
                        notNULL = true;
                        break;
                    }
                    for (auto x = firstSet.find(*j)->second.begin(); x != firstSet.find(*j)->second.end(); x++) {
                        if (*x != "$") {
                            firstSet[tempProduct.left].insert(*x);
                        }
                    }
                    if (!canInferNull(*j) || firstSet.find(*j)->second.find("$") != firstSet.find(*j)->second.end()) {
                        notNULL = true;
                        break;
                    }
                }
                if (!notNULL) {
                    firstSet[tempProduct.left].insert("$");
                }
            }
        }
        now_size = 0;
        for (auto i = firstSet.begin(); i != firstSet.end(); i++) {
            now_size += i->second.size();
        }
    }
}


itemSet itemSet::getNextNode(string str) {
    vector<item> newItems;
    for (auto i = items.begin(); i != items.end(); i++) {
        if (i->dotPos != i->rights.size() && i->rights[i->dotPos]._Equal(str)) {
            item newItem(i->left, i->rights, i->dotPos + 1, i->productIndex, i->symbols);
            newItems.push_back(newItem);
        }
    }
    itemSet set(0, newItems);
    return set;
}


bool itemSet::isRepeat(item temp)
{
    for (int i = 0; i < items.size(); i++) {
        if (items[i] == temp) {
            return true;
        }
    }
    return false;
}


product* LRanalsys::getProduct(int index)
{
    if (products.find(index) != products.end()) {
        return products.find(index)->second;
    }
    return nullptr;
}

void LRanalsys::getAllItemSets()
{
    // 初始节点 
    vector<item> firstItem;
    item first(*products[0]);
    first.symbols.insert("#");
    firstItem.push_back(first);
    itemSet firstSet(numberOfItemSet++, firstItem);
    getClosure(firstSet);
    itemSets.insert(make_pair(firstSet.index, firstSet));

    // 到了状态生成
    for (int i = 0; i < numberOfItemSet; i++) {
        itemSet& tempSet = itemSets[i];
        for (int j = 0; j < tempSet.items.size(); j++) {
            if (tempSet.items[j].dotPos != tempSet.items[j].rights.size()&&tempSet.items[j].rights[0] != "$" ) {
                getNextNode(tempSet, tempSet.items[j].rights[tempSet.items[j].dotPos]);
            }
        }
    }
}

void LRanalsys::readToken(string tokenName)
{
    fstream file;
    string line;
    token temp;
    int lineNumber;
    wordType type;
    file.open(tokenName, ios::in);

    if (!file.is_open()) {
        cout << "error: 打开token文件失败" << endl;
        exit(1);
    }


    while (getline(file, line)) {
        auto pos = line.find('\t');
        if (pos == string::npos) {
            cout << "error:  token文件错误" << endl;
            exit(1);
        }

        lineNumber = atoi(line.substr(0, pos).c_str());

        line.erase(0, pos+1);
        pos= line.find('\t');
        string wordtype = line.substr(0, pos);
        if (wordtype._Equal("KEYWORD")) {
            type=KEYWORD;
        }else if (wordtype._Equal("LIMIT")){
            type = LIMIT;
        }
        else if (wordtype._Equal("VARIABLE")) {
            type = VARIABLE;
        }
        else if (wordtype._Equal("OPERATION")) {
            type = OPERATION;
        }
        else if (wordtype._Equal("CONST")) {
            type = CONST;
        }
        line.erase(0, pos+1);


        temp = token(lineNumber, type, line);
        tokens.push_back(temp);
    }
    tokens.push_back(token(0, KEYWORD, "$"));
    tokens.push_back(token(0, KEYWORD, "#"));
}


void LRanalsys::analyseToken()
{
    // 根据构建好的项目转移图分析输入的token
    string tempSymbol;              // 要移入的符号
    int tempStatus;                 // 栈顶状态
    itemSet tempSet;                // 栈顶状态对应项目

    int count1 = 0;                 // 计数器

    for (auto i = itemSets.begin(); i != itemSets.end(); i++) {
        auto& tempSet = i->second;
        for (auto j = tempSet.items.begin(); j != tempSet.items.end(); j++) {
            if (j->rights[0] == "$")
                j->dotPos++;
        }
    }

    for (int num = 0; num < tokens.size(); ) {
        
        if (tokens[num].type == CONST){
            tempSymbol = "const";
        }
        else if (tokens[num].type == VARIABLE) {
            tempSymbol = "variable";
        }
        else {
            tempSymbol = tokens[num].value;
        }
        tempStatus = statusStack.back();
        tempSet = itemSets[tempStatus];


        // 移入当前符号
        bool action = false;
        for (auto j = tempSet.GOTO.begin(); j != tempSet.GOTO.end(); j++) {
            if (j->first._Equal(tempSymbol)) {
                statusStack.push_back(j->second);
                symbolsStack.push_back(tempSymbol);

                cout << "********  移入  *************** " << endl;
                cout << "移入符号:" << tempSymbol << endl;
                printStatusStack();
                printSymbolStack();
                cout << endl;
                action = true;
            }
        }

        if (action) {
            num++;
            count1 =0;
            continue;
        }

        count1++;

        if (count1 > 3) {
            cout << "error:文法错误,无法继续分析\t错误行号:" << tokens[num].lineNumber << endl;
            exit(1);
        }

        // 规约
        bool flag = false;
        for (auto j = tempSet.items.begin(); j != tempSet.items.end(); j++) {
            // 找到规约的产生式
            if (j->dotPos == j->rights.size() && j->symbols.find(tempSymbol) != j->symbols.end()) {

                if (flag) {
                    cout << "error:文法错误,无法继续分析\t错误行号:" << tokens[num].lineNumber << endl;
                    exit(1);
                }
                if (j->rights[0] == "$") {
                    tokens.insert(tokens.begin() + num, token(0, KEYWORD, "#"));
                }
                else {
                    for (int k = 0; k < j->rights.size(); k++) {
                        statusStack.pop_back();
                        symbolsStack.pop_back();
                    }
                }
                // 更新栈内状态
                symbolsStack.push_back(j->left);
                tempStatus = statusStack.back();
                itemSet set= itemSets[tempStatus];

                auto findRes = set.GOTO.find(j->left);
                if (findRes == set.GOTO.end() && symbolsStack.back()._Equal("ssstart")) {
                    cout << "success:成功接收" << endl;
                     exit(1);
                }
                if (findRes == set.GOTO.end())
                    continue;
                statusStack.push_back(findRes->second);
                cout << "********  规约  *************** " << endl;
                cout << "使用产生式: " << products[j->productIndex]->left << "->";
                for (auto s = products[j->productIndex]->right.begin(); s != products[j->productIndex]->right.end(); s++) {
                    cout << *s << " ";
                }
                cout << endl;
                printStatusStack();
                printSymbolStack();
                cout << endl;
                count1 = 0;
                if (tokens[num].value == "#" && num != tokens.size() - 1) {
                    num++;
                }
                if (tokens[num].value == "$") {
                    num++;
                }
            }
        }
    }
}

bool LRanalsys::isNonTerminal(string str)
{
    if (NonTerminal.find(str) != NonTerminal.end())
        return true;
    return false;
}

void LRanalsys::getClosure(itemSet &tempSet)
{
    // 遍历项目集中的每一个项目,当点后面的符号为终结符的时候
    // 把左端为此非终结符的产生式对应的项目添加到当前项目集中
    int size = tempSet.items.size();
    for (int i = 0; i < tempSet.items.size(); i++) {
        item tempItem = tempSet.items[i];
        if (tempItem.dotPos != tempItem.rights.size() && isNonTerminal(tempItem.rights[tempItem.dotPos])) {
            auto productList = sameLeftProduct[tempItem.rights[tempItem.dotPos]];
            set<string>sym = tempItem.symbols;
            vector<string> behind;
            for (int j = tempItem.dotPos + 1; j < tempItem.rights.size(); j++) {
                behind.push_back(tempItem.rights[j]);
            }
            for (int j = 0; j < productList.size(); j++) {
                product product = *products[productList[j]];
                item newItem(product);
                getSymbols(newItem.symbols, behind, sym);
                bool flag = false;
                for (int k = size; k < tempSet.items.size(); k++) {
                    if (tempSet.items[k].productIndex == newItem.productIndex) {
                        tempSet.items[k].symbols.insert(newItem.symbols.begin(), newItem.symbols.end());
                        flag = true;
                    }
                }
                if (flag == false) {
                    tempSet.items.push_back(newItem);
                }
            }
        }
    }
}

void LRanalsys::getSymbols(set<string> &symbols, vector<string> behind, set<string> sym)
{
    set<string> res;
    if (behind.empty()) {
        symbols = sym;
        return;
    }
    int i = 0;
    for (; i < behind.size(); i++) {
        // 终结符
        if (isTerminal(behind[i])) {
            res.insert(behind[i]);
            break;
        } 
        // 非终结符,不可以推出空时跳出循环
        res.insert(firstSet[behind[i]].begin(), firstSet[behind[i]].end());
        if (isNonTerminal(behind[i]) && !canInferNull(behind[i])) 
            break;
    }
    if (i == behind.size())
        res.insert(sym.begin(), sym.end());
    symbols = res;
}



bool LRanalsys::getNextNode(itemSet &tempSet, string str)
{
    auto temp = tempSet.getNextNode(str);
    if (temp.items.size() == 0)
        return false;
    else {
        getClosure(temp);
        int x = -1;
        if (isRepeatItemSet(temp,x)) {
            if (x != -1) {
                tempSet.GOTO.insert(make_pair(str, x));
            }
            return false;
        }
        else {
            temp.index = numberOfItemSet++;
            tempSet.GOTO.insert(make_pair(str, temp.index));
            itemSets.insert(make_pair(temp.index, temp));
        }
    }
    return true;
}

void LRanalsys::creatGOTO_ACTION() {
    itemSet tempSet;
    int numberOfSet = 0;
    for (auto i = itemSets.begin(); i != itemSets.end(); i++, numberOfItemSet++) {
        auto trans = i->second.GOTO;
        map<string, pair<char, int>> Action;
        map<string, int> Goto;
        for (auto j = trans.begin(); j != trans.end(); j++) {
            if (isTerminal(j->first)) {
                Action.insert(make_pair(j->first, make_pair('s', j->second)));
            }
            else if (isNonTerminal(j->first)) {
                Goto.insert(make_pair(j->first, j->second));
            }
        }
        for (auto j = i->second.items.begin(); j != i->second.items.end(); j++) {
            if (j->dotPos == j->rights.size()) {
                for (auto k = j->symbols.begin(); k != j->symbols.end(); k++) {
                    Action.insert(make_pair(*k, make_pair('r', j->productIndex)));
                }
            }
        }
        ACTION.push_back(Action);
        GOTO.push_back(Goto);
    }
}


void LRanalsys::printSymbolStack()
{
    cout << "当前符号栈的内容为:" << endl;
    for (int i = 0; i < symbolsStack.size(); i++) {
        cout << symbolsStack[i] << "\t";
    }
    cout << endl;
}

void LRanalsys::printStatusStack()
{
    cout << "当前状态栈的内容为:" << endl;
    for (int i = 0; i < statusStack.size(); i++) {
        cout << statusStack[i] << "\t";
    }
    cout << endl;
}





bool LRanalsys::isRepeatItemSet(itemSet set, int& repeatPos)
{
    for (auto i = itemSets.begin(); i != itemSets.end(); i++) {
        if (i->second == set) {
            repeatPos = i->first;
            return true;
        }
    }
    return false;
}


bool LRanalsys::isTerminal(string str)
{
    if (Terminal.find(str) != Terminal.end())
        return true;
    return false;
}


int main(int argc, char* argv[]) {

// 请不要删除这段  (*__*) 我盯着你呐
#ifndef __YYYTEST
    int timer = 5;
    while (timer--) {
        for (int i = 3; i > 0; i--) {
            Delay(1 * 1000);
            cout << "..." << endl;
        }
        cout << "正在运行中,请稍后" << endl;
    }
    Delay(1 * 1000);
    cout << "啪。。。运行完成" << endl;
#endif 



#ifdef _DEFAULT_TEXT
    dfaSet test("thirdTypeGrammar.txt", "program.txt", "token.yyy");
    LRanalsys LR("secondTypeGrammar.txt", "token.yyy");
    exit(1);
#else

    string grammer_3, grammer_2, progrem, token;

    cout << "输入三型文法:" << endl;
    cin >> grammer_3;
    cout << "输入待分析程序" << endl;
    cin >> progrem;
    cout << "输入token名,默认为  token.yyy" << endl;
    cin >> token;
    cout << "输入二型文法" << endl;
    cin >> grammer_2;

    dfaSet test(grammer_3, progrem, token);
    LRanalsys LR(grammer_2, token);
#endif 
    return 0;
}

—__— 个人写代码习惯不好有很多地方注释的都不好,大家有问题可以直接发到评论,我有时间会回复的

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

都说了不是我(y~yy)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值