编译原理 设计报告
任务 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;
}
—__— 个人写代码习惯不好有很多地方注释的都不好,大家有问题可以直接发到评论,我有时间会回复的
本文详细介绍了编译原理中的词法分析和语法分析过程。首先,使用DFA和NFA构造词法分析器,处理常规单词,识别关键词、标识符、常量等。然后,通过LL(1)或LR(1)方法创建语法分析器,处理2型文法,判断源代码是否符合文法规则。文中提供了相应的代码实现和例子,展示了编译器的关键组件和工作流程。

8385

被折叠的 条评论
为什么被折叠?



