赋值语句的语法制导翻译

后续已完善算术运算文法、赋值文法、布尔运算文法、if、while、do-while和复合语句文法,编译器项目已上传GitHub,https://github.com/sleep-jyx/compiler

一、需要的语义过程如下:

  1. newtemp()
    \quad每次调用送回一个代表新临时变量的序号,可认为是送回T1、T2这样的一些临时变量

  2. ENTRY(i)
    \quad用于查变量i的符号表入口地址

  3. GEN(OP,ARG1,ARG2,RESULT)
    \quad产生一个四元式,并填入四元式序列表

  4. E.PLACE
    \quad含义:与非终结符E相关联的语义变量(值),值为某变量的符号表入口地址或临时变量序号

二、 赋值表达式文法如下
(1)S→A(2)A→i=E(3)E→−E(4)E→E+E(5)E→E∗E(6)E→E/E(7)E→(E)(8)E→i\begin{aligned} &(1) S \rightarrow A \\ &(2) A \rightarrow i=E \\ &(3) E \rightarrow -E \\ &(4) E \rightarrow E+E \\ &(5) E \rightarrow E*E \\ &(6) E \rightarrow E/E \\ &(7) E \rightarrow (E) \\ &(8) E \rightarrow i \\ \end{aligned} ​(1)S→A(2)A→i=E(3)E→−E(4)E→E+E(5)E→E∗E(6)E→E/E(7)E→(E)(8)E→i​
三、语义子程序如下:

产生式 语义子程序 目标代码
(1) A→\rightarrow→i=E {
GEN( =, E.PLACE ,_,ENTRY(i) )
}
“MOV R0,” + E(1)E^{(1)}E(1).varName;
“MOV " +E.varName +”,R0"
(2) E→\rightarrow→-E(1)E^{(1)}E(1) {
T=newtemp();
GEN( @, E(1)E^{(1)}E(1).PLACE ,_,T );
E(1)E^{(1)}E(1).PLACE=T
}
“MOV R0,” +E(1)E^{(1)}E(1).varName ;
“NEG R0”;
“MOV " +E.varName +”,R0"
(3) E→\rightarrow→ E(1)E^{(1)}E(1)+E(2)E^{(2)}E(2) {
T=newtemp();
GEN( +,E(1)E^{(1)}E(1).PLACE , E(2)E^{(2)}E(2).PLACE ,T );
E.PLACE =T
}
“MOV R0,” +E(1)E^{(1)}E(1).varName;
“ADD R0,” +E(2)E^{(2)}E(2).varName ;
“MOV " +E+ " R0” ;
(4) E→\rightarrow→ E(1)E^{(1)}E(1) -E(2)E^{(2)}E(2) {
T=newtemp();
GEN( -,E(1)E^{(1)}E(1).PLACE , E(2)E^{(2)}E(2).PLACE ,T );
E.PLACE =T
}
“MOV R0,” +E(1)E^{(1)}E(1).varName;
“SUB R0,” +E(2)E^{(2)}E(2).varName ;
“MOV " +E+ " R0” ;
(5) E→E(1)×E(2)E \rightarrow E^{(1)} \times E^{(2)}E→E(1)×E(2) {
T=newtemp();
GEN( *,E(1)E^{(1)}E(1).PLACE , E(2)E^{(2)}E(2).PLACE ,T );
E.PLACE=T
}
“MOV AL,” +E(1)E^{(1)}E(1).varName;
“MOV BL,” +E(2)E^{(2)}E(2).varName ;
“MUL BL” ;
"MOV " +E.varName + “,AX” ;
(6) E→E(1)/E(2)E \rightarrow E^{(1)} / E^{(2)}E→E(1)/E(2) {
T=newtemp();
GEN( /,E(1)E^{(1)}E(1).PLACE , E(2)E^{(2)}E(2).PLACE ,T );
E.PLACE =T
}
“MOV AX,” +E(1)E^{(1)}E(1).varName;
“MOV BH,” +E(2)E^{(2)}E(2).varName ;
“DIV BH” ;
"MOV " +E.varName + “,AL” ;
(7) E→(E(1))E\rightarrow (E^{(1)})E→(E(1)) {
E.PLACE=E(1)E^{(1)}E(1).PLACE
}
(8) E→iE\rightarrow iE→i {
E.PLACE=ENTRY(i)
}

四、结果

  1. 程序输出LR(1)分析的GOTO关系和项集的部分截图:
  2. 构造LR(1)分析表:其中s表示移进、r表示规约、acc表示接受状态
  3. 对输入的赋值语句进行词法分析:
    输入串,为区分减法和负号,负号用@代替: a=@10*(2+5)/25-4 #
    词法分析结果(用二元组表示,左边是标号,右边是关键词),关键词表见下:
  4. 在对输入串进行LR(1)语法分析的同时进行翻译,中间代码用四元式表示:
  5. 将四元式序列翻译为目标代码(汇编语言)

五、源程序

#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <fstream>
using namespace std;/*********************************************************                                                      **                第一部分:词法分析                       *  *                                                      ********************************************************/
// 关键字表置初始值
string Cppkeyword[100] = {"#", "标识符(变量名)", "整数", "实数", "字符常量", "+", "-", "*", "/", "<","<=", "==", "!=", ">", ">=", "&", "&&", "||", "=", "(",")", "[", "]", "{", "}", ":", ";", ",", "@", "!","void", "int", "float", "char", "if", "else", "while", "do", "for", "include","iostream", "using", "namespace", "std", "main", "return", "null"};
class word
{public:int syn{};string token;
};
//存储词法分析结果
word lexicalTable[1000];
int lexicalTableLen = 0;// 处理关键词和变量的函数
word letterAnalysis(const string &subCode)
{word item;int isKeyword = 0;for (int i = 30; i <= 46; i++){if (subCode.substr(0, Cppkeyword[i].length()) == Cppkeyword[i]){item.syn = i;isKeyword = 1;}}/* 不用上述for循环的话就得如下一一列举,如果关键词数目较多,就要写很多低级代码if (subCode.substr(0, 4) == "void"){item.syn = 28;}else if (subCode.substr(0, 3) == "int"){item.syn = 29;}else if (subCode.substr(0, 5) == "float")
*/if (isKeyword == 0){// 如果不是上述关键词,一律视为变量名for (int i = 0; i <= subCode.length(); ++i){ //找到第一个不是数字、字母、下划线的位置if (!(subCode[i] >= 'a' && subCode[i] <= 'z' || subCode[i] >= '0' && subCode[i] <= '9' || subCode[i] == '_')){item.syn = 1; //1号位存储变量名Cppkeyword[item.syn] = subCode.substr(0, i);break;}}}item.token = Cppkeyword[item.syn];return item;
}// 处理数字的函数
word numberAnalysis(string subCode)
{word item;for (int i = 0; i <= subCode.length(); ++i){// 截取到第一个非数字和小数点字符if (!(subCode[i] >= '0' && subCode[i] <= '9' || subCode[i] == '.')){string curNum = subCode.substr(0, i);if (curNum.find('.') == string::npos) //没读到'.'返回值为很大的数,若读到返回值是第一次出现的下标item.syn = 2;                     //2号位存整数elseitem.syn = 3; //3号位存实数Cppkeyword[item.syn] = curNum;break;}}item.token = Cppkeyword[item.syn];return item;
}// 处理字符常量的函数
word strAnalysis(string subCode)
{ //"hello"<<endl;word item;int nextindex = subCode.find_first_of('"', 1); //找到第二个"出现的位置下标item.syn = 4;                                  //字符常量置为4Cppkeyword[item.syn] = subCode.substr(0, nextindex + 1);item.token = Cppkeyword[item.syn];return item;
}// 处理字符的函数
word charAnalysis(string subCode)
{word item;switch (subCode[0]){case '#':item.syn = 0;break;case '+':item.syn = 5;break;case '-':item.syn = 6;break;case '*':item.syn = 7;break;case '/':item.syn = 8;break;case '<':if (subCode[1] == '='){item.syn = 10;}else{item.syn = 9;}break;case '=':if (subCode[1] == '='){item.syn = 11;}else{item.syn = 18;}break;case '!':if (subCode[1] == '='){item.syn = 12;}elseitem.syn = 29;break;case '>':if (subCode[1] == '='){item.syn = 14;}else{item.syn = 13;}break;case '&':if (subCode[1] == '&'){item.syn = 16;}else{item.syn = 15;}break;case '|':if (subCode[1] == '|'){item.syn = 17;}break;case '(':item.syn = 19;break;case ')':item.syn = 20;break;case '[':item.syn = 21;break;case ']':item.syn = 22;break;case '{':item.syn = 23;break;case '}':item.syn = 24;break;case ':':item.syn = 25;break;case ';':item.syn = 26;break;case ',':item.syn = 27;break;case '@':item.syn = 28;break;}item.token = Cppkeyword[item.syn];return item;
}// 词法分析
void scanner(const string &code)
{ //if a=1;for (int i = 0; i < code.length(); ++i){word item;if (code[i] >= 'a' && code[i] <= 'z'){// 处理单词,假设句子是 if a=1;进行单词分析后返回“if”,i后移了两位,这点在该函数最后有做处理item = letterAnalysis(code.substr(i, code.length() - i + 1));}else if (code[i] >= '0' and code[i] <= '9'){// 处理数字item = numberAnalysis(code.substr(i, code.length() - i + 1));}else if (code[i] == ' '){// 如果是空格,直接跳过continue;}else{// 处理特殊符号item = charAnalysis(code.substr(i, code.length() - i + 1));}i += int(item.token.length()) - 1;lexicalTable[lexicalTableLen++] = item; //词法处理完的结果存入lexicalTable中cout << "(" << item.syn << "," << item.token << ")" << endl;}
}/*****************************************************************                                                              **        第二部分、语法分析前的一些准备工作,主要包括:                 *      *      (1) 扫描文法,获取文法中出现的所有的Vn和Vt                    *  *      (2) 将文法中的产生式拆分为左部、右部,其中右部采用vector进行保存  **      (3) 构造所有Vn和Vt的first集和follow集                      * *                                                              *****************************************************************/
vector<string> grammar;          //存储文法
map<string, int> VN2int, VT2int; //VN、VT映射为下标索引
int symbolNum = 0;
map<string, bool> nullable; //各终结符或非终结符是否可空
set<string> first[50];      //存储各Vn和Vt的first集,没错,Vt也构造first集,就是其自身
set<string> follow[50];     //存储各Vn和Vt的follow集,Vt的follow都是空,240~263行取消注释可查看Vt的first和follow集string getVn(string grammar)
{ //获取文法中的非终结符if (grammar[1] == '\''){ //带'的非终结符,如 E',T'return grammar.substr(0, 2);}else{ //不带'的正常非终结符,如E,Treturn grammar.substr(0, 1);}
}string getVt(string grammar)
{ //获取文法中的终结符//Cppkeyword[1] = "i";for (int k = 0; k <= 46; k++){string Vt = grammar.substr(0, Cppkeyword[k].length());if (Vt == Cppkeyword[k]){return Vt;}}//如果运行到这里,说明这个终结符不是关键词表里的,认为小写字母也属于终结符if (grammar[0] >= 'a' && grammar[0] <= 'z'){return grammar.substr(0, 1);}
}
void readVnAndVt()
{//扫描一个产生式,识别所有的非终结符和终结符for (int i = 0; i < grammar.size(); i++){for (int j = 0; j < grammar[i].length(); j++){if (grammar[i][j] >= 'A' && grammar[i][j] <= 'Z'){ //非终结符一般大写string Vn = getVn(grammar[i].substr(j, 2));if (VN2int[Vn] == 0)VN2int[Vn] = ++symbolNum;j = j + Vn.length() - 1;}else if (grammar[i].substr(j, 2) == "->"){j = j + 2 - 1;}else{ //扫描产生式右部的可能的终结符(关键词表)string Vt = getVt(grammar[i].substr(j, grammar[i].length() - j));if (VT2int[Vt] == 0)//该终结符第一次出现,将该终结符映射为下标索引VT2int[Vt] = ++symbolNum;j = j + Vt.length() - 1;}}}cout << "非终结符VN:" << endl;for (auto it = VN2int.begin(); it != VN2int.end(); it++){cout << "索引下标:" << it->second << "\t名称:" << it->first << endl;}cout << "终结符VT:" << endl;for (auto it = VT2int.begin(); it != VT2int.end(); it++){cout << "索引下标:" << it->second << "\t名称:" << it->first << endl;}
}vector<string> splitGrammarIntoYi(string rightGrama)
{ //将产生式的右部(左部->右部拆分):X->Y1Y2...Ykvector<string> Y;for (int j = 0; j < rightGrama.length(); j++){if (rightGrama[j] >= 'A' && rightGrama[j] <= 'Z'){ //非终结符string Vn = getVn(rightGrama.substr(j, 2));Y.push_back(Vn);j = j + Vn.length() - 1;}else{ //终结符string Vt = getVt(rightGrama.substr(j, rightGrama.length() - j));Y.push_back(Vt);j = j + Vt.length() - 1;}}return Y;
}void split(string grama, string &X, vector<string> &Y)
{int delimiterIndex = grama.find("->");X = grama.substr(0, delimiterIndex);string rightGrama = grama.substr(delimiterIndex + 2, grama.length() - delimiterIndex - 2);Y = splitGrammarIntoYi(rightGrama);
}bool allNullable(vector<string> Y, int left, int right)
{ //判断 Y[left]...Y[right]是否全可空if (left >= Y.size() || left > right || right < 0)return true;for (int i = left; i <= right; i++){if (nullable[Y[i]] == false)return false;}return true;
}void getFirstFollowSet()
{/*计算FIRST、FOLLOW、nullable的算法*/for (auto it = VT2int.begin(); it != VT2int.end(); it++){ //对每一个终结符Z,first[Z]={Z}string Vt = it->first;int Vt_index = it->second;first[Vt_index].insert(Vt);}for (int grammarIndex = 0; grammarIndex < grammar.size(); grammarIndex++){//对于每个产生式:X->Y1Y2...Ykstring X;vector<string> Y;int delimiterIndex = grammar[grammarIndex].find("->");X = grammar[grammarIndex].substr(0, delimiterIndex);                                                                       //以"->"为界,分隔产生式string rightGrama = grammar[grammarIndex].substr(delimiterIndex + 2, grammar[grammarIndex].length() - delimiterIndex - 2); //提取左部产生式Y = splitGrammarIntoYi(rightGrama);int k = Y.size();nullable["null"] = true;//如果所有Yi都是可空的,则nullable[X]=trueif (allNullable(Y, 0, k - 1)){nullable[X] = true;}for (int i = 0; i < k; i++){//如果Y0...Y(i-1)都是可空的(言外之意Yi不空),则first[X] = first[X]∪first[Yi] (1)if (nullable[Y[i]] == false && allNullable(Y, 0, i - 1)){if (i <= k - 1){set<string> setX = first[VN2int[X]];//判断Yi是终结符还是非终结符set<string> setY = VT2int.count(Y[i]) != 0 ? first[VT2int[Y[i]]] : first[VN2int[Y[i]]];set_union(setX.begin(), setX.end(), setY.begin(), setY.end(), inserter(setX, setX.begin())); //(1)first[VN2int[X]] = setX;}}//如果Y(i+1)...Yk都是可空的(言外之意Y0..Y(i-1)都不空),则follow[Yi] = follow[Yi]∪follow[X] (2)if (allNullable(Y, i + 1, k - 1)){set<string> setX = follow[VN2int[X]];//判断Yi是终结符还是非终结符set<string> setY = VT2int.count(Y[i]) ? follow[VT2int[Y[i]]] : follow[VN2int[Y[i]]];set_union(setX.begin(), setX.end(), setY.begin(), setY.end(), inserter(setY, setY.begin()));VT2int.count(Y[i]) ? follow[VT2int[Y[i]]] : follow[VN2int[Y[i]]] = setY;}for (int j = i + 1; j < k; j++){//如果Y(i+1)...Y(j-1)都是可空的(言外之意Yj不空),则follow[Yi] = follow[Yi]∪first[Yj] (3)if (nullable[Y[j]] == false && allNullable(Y, i + 1, j - 1)){if (j <= k - 1){set<string> setYi = VT2int.count(Y[i]) ? follow[VT2int[Y[i]]] : follow[VN2int[Y[i]]];set<string> setYj = VT2int.count(Y[j]) ? first[VT2int[Y[j]]] : first[VN2int[Y[j]]];set_union(setYi.begin(), setYi.end(), setYj.begin(), setYj.end(), inserter(setYi, setYi.begin()));VT2int.count(Y[i]) ? follow[VT2int[Y[i]]] : follow[VN2int[Y[i]]] = setYi;}}}}}
}void converge()
{ //迭代计算first和follow集,直到收敛set<string> oldFirst[50];set<string> oldFollow[50];int isConverge = 1;string _vn = getVn(grammar[0].substr(0, 2));//这是一个可以手动修改的地方,很多教材的终止符不一样,这里统一一下,都用#作为终止符follow[VN2int[_vn]].insert("#");int times = 1; //经过多少轮才收敛do{ //非终结符的first、follow不再变化则收敛isConverge = 1;getFirstFollowSet();//VN的状态for (auto it = VN2int.begin(); it != VN2int.end(); it++){int vnindex = it->second;if (oldFirst[vnindex].size() != first[vnindex].size() || oldFollow[vnindex].size() != follow[vnindex].size())isConverge = 0;//保存旧状态,以便之后和新状态比较是否变化判断收敛与否oldFirst[vnindex] = first[vnindex];oldFollow[vnindex] = follow[vnindex];}} while (isConverge != 1);//输出最终结果cout << endl;for (auto it = VN2int.begin(); it != VN2int.end(); it++){int vnindex = it->second;if (oldFirst[vnindex].size() != first[vnindex].size() || oldFollow[vnindex].size() != follow[vnindex].size()){isConverge = 0;}//输出状态cout << it->first << "的first集:\t";for (auto first_it = first[vnindex].begin(); first_it != first[vnindex].end(); first_it++){cout << *first_it << " ";}cout << "\t" << it->first << "的follow集:\t";for (auto follow_it = follow[vnindex].begin(); follow_it != follow[vnindex].end(); follow_it++){cout << *follow_it << " ";}cout << endl;}
}/*****************************************************************                                                              **                  第三部分:构造文法的LR1分析表                   **          关键函数:(1) closure():计算项集的LR1闭包               **                  (2) GOTO():由项集I读入Vn或Vt转向项集J          **                                                              *****************************************************************/
struct term
{                 //LR1项集内部的项int termType; //移进项目、待约项目、规约项目string leftPart;vector<string> rightPart;int dotPos{-1};             //活前缀在右部的位置,初始化为-1vector<string> subsequence; //LR1文法才用到的后继符,随便初始化一个字符串bool operator==(const term &b) const{if (leftPart == b.leftPart && rightPart == b.rightPart && dotPos == b.dotPos){if (subsequence == b.subsequence)return true;}return false;}
};
vector<term> statusSet[50]; //项集
int globalStatusNum = 1;
int actionTable[50][50]; //action表,行表示状态,列表示终结符
int gotoTable[50][50];   //goto表,行表示状态,列表示非终结符void initGrammar()
{//表达式文法,用LR(0)构造存在冲突,用SLR可以消除冲突/* grammar.push_back("E'->E");grammar.push_back("E->E+T");grammar.push_back("E->T");grammar.push_back("T->T*F");grammar.push_back("T->F");grammar.push_back("F->(E)");grammar.push_back("F->i");*///该文法使用SLR仍有冲突(哈工大mooc例子),使用LR1分析无冲突/*grammar.push_back("S'->S");grammar.push_back("S->L=R");grammar.push_back("S->R");grammar.push_back("L->*R");grammar.push_back("L->i");grammar.push_back("R->L");*///龙书本科版,LR1例子,验证正确/*grammar.push_back("S'->S");grammar.push_back("S->CC");grammar.push_back("C->cC");grammar.push_back("C->d");
*///赋值语句文法grammar.push_back("S'->A");grammar.push_back("A->i=E");grammar.push_back("E->@E");grammar.push_back("E->E+E");grammar.push_back("E->E-E");grammar.push_back("E->E*E");grammar.push_back("E->E/E");grammar.push_back("E->(E)");grammar.push_back("E->i");/*//习题册P184习题,成功构造(另外发现:如果程序没错的话,就是题目给的答案有点问题)grammar.push_back("Z->S");grammar.push_back("S->L=R");grammar.push_back("S->R");grammar.push_back("R->L");grammar.push_back("L->*R");grammar.push_back("L->I");*///习题册P189习题/*grammar.push_back("S'->S");grammar.push_back("S->Aa");grammar.push_back("S->dAb");grammar.push_back("S->Bb");grammar.push_back("S->dBa");grammar.push_back("A->c");grammar.push_back("B->c");*/
}//该函数作用:项集I读入Vn或Vt可能会生成新的项集J,但也有可能指向已有项集,该函数就是判断是否指向已有项集
int mergeSet()
{int flag = -1; //假定不可以进行合并for (int i = 0; i < globalStatusNum - 1; i++){if (statusSet[globalStatusNum - 1].size() != statusSet[i].size())continue;flag = i; //可以和状态集i合并for (int j = 0; j < statusSet[globalStatusNum - 1].size(); j++){if (!(statusSet[i][j] == statusSet[globalStatusNum - 1][j])){flag = -1;}}if (flag != -1) //第一次遇到可以合并的集合就结束,不然等到后面会遇到项目数相等但状态集不同的情况return flag;}return -1;
}void initI0()
{term firstTerm;string X;vector<string> Y;split(grammar[0], X, Y);if (firstTerm.dotPos == -1) //如果没有活前缀"·"firstTerm.dotPos = 0;   //就添加活前缀firstTerm.leftPart = X;firstTerm.rightPart = Y;firstTerm.subsequence.push_back("#");statusSet[0].push_back(firstTerm);
}//相对于LR0和SLR,LR1在closure这个函数中有大改动,几乎是重写
void closure(int statusNum)
{ //计算LR1文法的项集闭包queue<term> termQueue;for (int i = 0; i < statusSet[statusNum].size(); i++)termQueue.push(statusSet[statusNum][i]);while (!termQueue.empty()){ //对项集I中每个项[A->a·B beta,alpha]term curTerm = termQueue.front();if (curTerm.dotPos == curTerm.rightPart.size()) //如果是规约项,跳过并弹出该项{termQueue.pop();continue;}string B = curTerm.rightPart[curTerm.dotPos];for (int j = 0; j < grammar.size(); j++){ //对增广文法G'中的每个产生式B->gammaif (B != getVn(grammar[j].substr(0, 2)))continue;//将[B->·gamma,b]加入集合I中,其中b是FIRST[beta alpha]中的终结符term newTerm;newTerm.dotPos = 0;split(grammar[j], newTerm.leftPart, newTerm.rightPart);//warning:好像没考虑B->null的情况,还是说已经考虑了(null看成终结符)if (VT2int.count(newTerm.rightPart[0]) != 0) //B->·bA,移进项目newTerm.termType = 2;else if (VN2int.count(newTerm.rightPart[0]) != 0) //B->b·A,待约项目newTerm.termType = 3;//找bstring beta;vector<string> b;if (curTerm.dotPos == curTerm.rightPart.size() - 1){ //如果beta不存在,b即alphab = curTerm.subsequence;}else if (VT2int.count(curTerm.rightPart[curTerm.dotPos + 1]) != 0){ //如果beta存在,b为first(beta)。特例:beta为终结符时,b就是betab.push_back(curTerm.rightPart[curTerm.dotPos + 1]);}else{ //遍历first(beta)中的终结符bbeta = curTerm.rightPart[curTerm.dotPos + 1];for (auto it = first[VN2int[beta]].begin(); it != first[VN2int[beta]].end(); it++){b.push_back(*it);}}newTerm.subsequence = b;//只有闭包生成的新项B->gamma,不在集合I中才加入;在集合I中的只要相应的增加后继符int newTermFlag = -1; //先假设不在集合I中for (int k = 0; k < statusSet[statusNum].size(); k++){if (newTerm.leftPart == statusSet[statusNum][k].leftPart && newTerm.rightPart == statusSet[statusNum][k].rightPart && newTerm.dotPos == statusSet[statusNum][k].dotPos)newTermFlag = k;}if (newTermFlag == -1){ //不在集合I中就加入termQueue.push(newTerm);statusSet[statusNum].push_back(newTerm);}else{ //如果新项B->gamma在集合I中,就新增其后继符(如果有新后继符的话)map<string, int> subsequenceMap;for (int m = 0; m < statusSet[statusNum][newTermFlag].subsequence.size(); m++){subsequenceMap[statusSet[statusNum][newTermFlag].subsequence[m]]++;}for (int m = 0; m < newTerm.subsequence.size(); m++){if (subsequenceMap[newTerm.subsequence[m]] == 0)statusSet[statusNum][newTermFlag].subsequence.push_back(newTerm.subsequence[m]);}}}termQueue.pop();}
}//GOTO函数无须变动,不管是LR0,SLR,LR1分析,都是从集合I读入一个符号经过闭包运算得到集合J。goto函数内部调用了closure()。
int GOTO(int statusNum, string symbol)
{ //由状态集statusNum读入一个符号symbol(vn或vt),返回转移后的项集编号int size = statusSet[statusNum].size();for (int i = 0; i < size; i++){vector<string> right = statusSet[statusNum][i].rightPart;int dotPos = statusSet[statusNum][i].dotPos;//symbol是vn或者vt都可if (dotPos < right.size() && symbol == right[dotPos]){term tmpTerm = statusSet[statusNum][i];tmpTerm.dotPos = tmpTerm.dotPos + 1; //活前缀后移一位dotPos = tmpTerm.dotPos;//如果后移一位之后发现成为了规约项目,则加入新项目集if (tmpTerm.dotPos == tmpTerm.rightPart.size()){tmpTerm.termType = 4;statusSet[globalStatusNum].push_back(tmpTerm);}else if (VT2int.count(tmpTerm.rightPart[dotPos]) != 0){ //活前缀不在最后,且紧随着一个终结符(移进项目),加入新项目tmpTerm.termType = 2;statusSet[globalStatusNum].push_back(tmpTerm);}else if (VN2int.count(tmpTerm.rightPart[dotPos]) != 0){ //活前缀不在最后,且紧随着一个非终结符(待约项目),将上一个状态集中的该非终结符产生式加入//先加入 S->B·BtmpTerm.termType = 3;statusSet[globalStatusNum].push_back(tmpTerm);//再进行闭包计算closure(globalStatusNum);}}}globalStatusNum++;int flag = mergeSet();if (flag != -1) //可合并{statusSet[globalStatusNum - 1].clear(); //清空,以防万一globalStatusNum--;return flag;}elsereturn globalStatusNum - 1;
}void printStatus()
{//输出状态集for (int i = 0; i < globalStatusNum; i++){cout << "┌───────────────────────┐" << endl;cout << "│      I" << i << "\t\t│" << endl;cout << "├───────────────────────┤" << endl;for (auto it = statusSet[i].begin(); it != statusSet[i].end(); it++){cout << "│";cout << it->leftPart << "->";for (int j = 0; j < it->rightPart.size(); j++){if (j == it->dotPos)cout << "·";cout << it->rightPart[j];}if (it->rightPart.size() == it->dotPos)cout << "·";for (int j = 0; j < it->subsequence.size(); j++){if (j == 0)cout << "," << it->subsequence[j];elsecout << "_" << it->subsequence[j];}cout << "     \t│" << endl;}cout << "└───────────────────────┘" << endl;}
}void printTable()
{//输出分析表cout << " \t";for (auto it = VT2int.begin(); it != VT2int.end(); it++)cout << it->first << " \t";for (auto it = VN2int.begin(); it != VN2int.end(); it++){ //goto表跳过增广文法的左部if (it->first == getVn(grammar[0].substr(0, 2)))continue;cout << it->first << "\t";}cout << endl;for (int i = 0; i < globalStatusNum; i++){cout << i << "\t";for (auto it = VT2int.begin(); it != VT2int.end(); it++){ //action,移进(大100)、规约(大1000)、接受if (actionTable[i][it->second] >= 100 && actionTable[i][it->second] < 1000)cout << "s" << actionTable[i][it->second] - 100 << "\t";else if (actionTable[i][it->second] >= 1000 && actionTable[i][it->second] < 10000)cout << "r" << actionTable[i][it->second] - 1000 << "\t";else if (actionTable[i][it->second] == 10000)cout << "acc\t";elsecout << actionTable[i][it->second] << " \t";}for (auto it = VN2int.begin(); it != VN2int.end(); it++){ //goto表跳过增广文法的左部if (it->first == getVn(grammar[0].substr(0, 2)))continue;cout << gotoTable[i][it->second] << "\t";}cout << endl;}
}//相比LR0和SLR,LR1分析表只对规约项进行改动(项种类:移进项(不变)、接受项(?)、GOTO项(不变))
//删了十几行,加了1行就ok了
void constructStatusSet(int choice = 0)
{ //同步构造项集和分析表initI0();closure(0);queue<string> symbolToRead;map<string, int> symbolMap;int curStatus = 0; //队列中当前项的状态for (int i = 0; i < statusSet[0].size(); i++){string symbolStr = statusSet[0][i].rightPart[statusSet[0][i].dotPos];if (symbolMap[symbolStr] == 0){symbolToRead.push(symbolStr);symbolMap[symbolStr]++;}}symbolToRead.push("sep"); //加入分隔项while (!symbolToRead.empty()){if (symbolToRead.front() == "sep"){ //一个项集的移进项和goto项都处理完毕之后,开始处理规约项for (int ii = 0; ii < statusSet[curStatus].size(); ii++){/****action表规约项构造****/if (statusSet[curStatus][ii].dotPos == statusSet[curStatus][ii].rightPart.size()){ //判断该规约项是用哪个产生式规约的term tmpTerm = statusSet[curStatus][ii];string reduceTerm = tmpTerm.leftPart + "->";for (int ii = 0; ii < tmpTerm.rightPart.size(); ii++)reduceTerm = reduceTerm + tmpTerm.rightPart[ii];int genNum = -1;for (int ii = 0; ii < grammar.size(); ii++)if (reduceTerm == grammar[ii])genNum = ii;//接受状态if (genNum == 0)actionTable[curStatus][VT2int["#"]] = 10000;else{//LR(1)分析中,只有规约项的后继符才进行规约for (int _i = 0; _i < tmpTerm.subsequence.size(); _i++)actionTable[curStatus][VT2int[tmpTerm.subsequence[_i]]] = 1000 + genNum; //同样为避免编号冲突,规约项全体加1000}}continue;}/****action表规约项填充完毕*****/curStatus++;symbolToRead.pop();continue;}int nextStatus = GOTO(curStatus, symbolToRead.front());cout << "I" << curStatus << "--" << symbolToRead.front() << "-->"<< "I" << nextStatus;//action表移入项填充if (VT2int.count(symbolToRead.front()) != 0){if (actionTable[curStatus][VT2int[symbolToRead.front()]] != 0)cout << "(状态" << curStatus << "移进" << symbolToRead.front() << "存在冲突)";actionTable[curStatus][VT2int[symbolToRead.front()]] = 100 + nextStatus;}else //goto表填充gotoTable[curStatus][VN2int[symbolToRead.front()]] = nextStatus;cout << endl;//新状态集的活前缀后面的符号(包括vn和vt)入队列,若产生的状态集是已有的状态集的就不用了if (nextStatus == globalStatusNum - 1){symbolMap.clear();for (int ii = 0; ii < statusSet[nextStatus].size(); ii++){//规约项就跳过if (statusSet[nextStatus][ii].dotPos == statusSet[nextStatus][ii].rightPart.size())continue;string symbolStr = statusSet[nextStatus][ii].rightPart[statusSet[nextStatus][ii].dotPos];if (symbolMap[symbolStr] == 0){symbolToRead.push(symbolStr);symbolMap[symbolStr]++;}}symbolToRead.push("sep"); //引入分隔项}symbolToRead.pop();}printStatus(); //输出状态项集printTable();  //输出分析表
}/************************************************************************                                                                     ** 第四部分:使用第三部分生成的LR1分析表对赋值表达式进行语法分析,               **         边语法分析边进行语法制导翻译,生成四元式序列和汇编代码               **                                                                     **   (1) GEN():输出四元式;并将目的操作数与符号表中的相应符号进行绑定或注册      **   (2) translate():对输入串边进行语法分析边翻译为四元式序列(规约时翻译)      **   (3) translateToAssembly():根据语义子程序的汇编形式将四元式翻译为汇编代码  **                                                                     ************************************************************************/struct Symbol
{string varName;       //变量名string valueStr{"0"}; //变量的值,字符串形式,初始化为0int PLACE{-1};        //该变量在符号表中的位置,初始化为-1
};
struct FourYuanFormula
{                  //四元式结构体string op;     //操作符int arg1Index; //源操作数1的符号表地址int arg2Index; //源操作数2的符号表地址Symbol result; //目的操作数
};
vector<FourYuanFormula> formula; //四元式序列
vector<Symbol> symbolTable;      //符号表
map<string, int> ENTRY;          //用于查变量的符号表入口地址
int tempVarNum = 0;              //临时变量个数
Symbol newtemp()
{ //生成新的临时变量tempVarNum++;return Symbol{"T" + to_string(tempVarNum)};
}void GEN(string op, int arg1, int arg2, Symbol &result)
{ //运算符、参数1在符号表的编号、参数2在符号表的编号,结果符号//产生一个四元式,并填入四元式序列表cout << "(" << op << ",";arg1 != -1 ? cout << symbolTable[arg1].varName : cout << "_";cout << ",";arg2 != -1 ? cout << symbolTable[arg2].varName : cout << "_";cout << "," << result.varName << ")" << endl;formula.push_back(FourYuanFormula{op, arg1, arg2, result}); //插入到四元式序列中if (op == "@"){ //将临时变量result注册进入符号表result.varName;result.PLACE = symbolTable.size();result.valueStr = "-" + symbolTable[arg1].valueStr;symbolTable.push_back(result);ENTRY[result.varName] = result.PLACE;}if (op == "+"){ //将临时变量result注册进入符号表result.PLACE = symbolTable.size();result.valueStr = to_string(stoi(symbolTable[arg1].valueStr) + stoi(symbolTable[arg2].valueStr));symbolTable.push_back(result);ENTRY[result.varName] = result.PLACE;}if (op == "-"){ //将临时变量result注册进入符号表result.PLACE = symbolTable.size();result.valueStr = to_string(stoi(symbolTable[arg1].valueStr) - stoi(symbolTable[arg2].valueStr));symbolTable.push_back(result);ENTRY[result.varName] = result.PLACE;}if (op == "*"){ //将临时变量result注册进入符号表result.PLACE = symbolTable.size();result.valueStr = to_string(stoi(symbolTable[arg1].valueStr) * stoi(symbolTable[arg2].valueStr));symbolTable.push_back(result);ENTRY[result.varName] = result.PLACE;}if (op == "/"){ //将临时变量result注册进入符号表result.PLACE = symbolTable.size();result.valueStr = to_string(stoi(symbolTable[arg1].valueStr) / stoi(symbolTable[arg2].valueStr));symbolTable.push_back(result);ENTRY[result.varName] = result.PLACE;}if (op == "=") //这个result不是临时变量了,故不用注册进入符号表,只进行绑定result.valueStr = symbolTable[arg1].valueStr;
}void translate()
{cout << "—————————————赋值表达式翻译为四元式序列———————————————————" << endl;//需要三个栈:状态栈、符号栈、语义栈stack<int> status;      //状态栈stack<Symbol> op;       //符号栈stack<string> semantic; //语义栈int pointer = 0;        //输入串指针status.push(0);         //状态栈初始化op.push(Symbol{"#"});   //符号栈初始化,{name、value、place}while (!op.empty()){int curStatus = status.top();                      //当前状态string symbolToRead = lexicalTable[pointer].token; //读头符号//读头不论是变量还是数字都当做终结符i处理(因为分析表中只有i这个终结符可以代表这些)if (lexicalTable[pointer].syn == 1 || lexicalTable[pointer].syn == 2) //1是变量,2是整数{symbolToRead = "i";semantic.push(lexicalTable[pointer].token); //语义栈//将语义加入符号表,并添加入口地址映射Symbol tempSym; //讲道理,如果是变量应该只有变量名没有值(至少在未初始化和未赋值前),而整数应该只有值而没有变量名。为兼顾两者,有如下处理tempSym.varName = lexicalTable[pointer].token;tempSym.valueStr = lexicalTable[pointer].token;tempSym.PLACE = symbolTable.size();symbolTable.push_back(tempSym);ENTRY[tempSym.varName] = tempSym.PLACE;}//goto原状态下标,移进项+100,规约项+1000,接受态10000if (actionTable[curStatus][VT2int[symbolToRead]] >= 100 && actionTable[curStatus][VT2int[symbolToRead]] < 1000){ //由上一个状态读入一个终结符转入新状态status.push(actionTable[curStatus][VT2int[symbolToRead]] - 100);op.push(Symbol{symbolToRead});pointer++;}else if (actionTable[curStatus][VT2int[symbolToRead]] >= 1000 && actionTable[curStatus][VT2int[symbolToRead]] < 10000){ //规约项,由上一个状态读入一个终结符int reduceGrammaIndex = actionTable[curStatus][VT2int[symbolToRead]] - 1000;term reduceTerm;split(grammar[reduceGrammaIndex], reduceTerm.leftPart, reduceTerm.rightPart);if (reduceGrammaIndex == 1){ //A->i=ESymbol E, i;for (int popTime = 0; popTime < 3; popTime++){if (popTime == 0)E = op.top();if (popTime == 2)i = op.top();op.pop();status.pop();}op.push(Symbol{reduceTerm.leftPart});curStatus = status.top();status.push(gotoTable[curStatus][VN2int[op.top().varName]]);GEN("=", E.PLACE, -1, i);}else if (reduceGrammaIndex == 2){ //E->@ESymbol E1 = op.top();int popNum = reduceTerm.rightPart.size();while (popNum){status.pop();op.pop();popNum--;}op.push(Symbol{reduceTerm.leftPart});curStatus = status.top();status.push(gotoTable[curStatus][VN2int[op.top().varName]]);Symbol T = newtemp();GEN("@", E1.PLACE, -1, T);semantic.pop(); //更新语义栈semantic.push(T.varName);op.top().PLACE = T.PLACE;op.top().valueStr = T.valueStr;}else if (reduceGrammaIndex >= 3 && reduceGrammaIndex <= 6){ //E->E 加减乘除 E ,规约Symbol E1, E2;for (int popTime = 0; popTime < 3; popTime++){ //E->E + E 要出栈三次,进栈一次if (popTime == 0)E2 = op.top();if (popTime == 2)E1 = op.top();op.pop();status.pop();}op.push(Symbol{reduceTerm.leftPart}); //把"E"push进符号栈,但还没和语义栈关联,下面进行curStatus = status.top();status.push(gotoTable[curStatus][VN2int[op.top().varName]]);Symbol T = newtemp();string opStr[4] = {"+", "-", "*", "/"};GEN(opStr[reduceGrammaIndex - 3], E1.PLACE, E2.PLACE, T);semantic.pop(); //更新语义栈semantic.pop();semantic.push(T.varName);op.top().PLACE = T.PLACE;op.top().valueStr = T.valueStr;}else if (reduceGrammaIndex == 7){ //E->(E)Symbol E1;for (int popTime = 0; popTime < 3; popTime++){if (popTime == 1)E1 = op.top();op.pop();status.pop();}op.push(Symbol{reduceTerm.leftPart}); //把"E"push进符号栈,但还没和语义栈关联,下面进行curStatus = status.top();status.push(gotoTable[curStatus][VN2int[op.top().varName]]);op.top().PLACE = ENTRY[semantic.top()]; //E.PLACE = ENTRY(i)semantic.pop();}else if (reduceGrammaIndex == 8){ //E->iint popNum = reduceTerm.rightPart.size();while (popNum){status.pop();op.pop();popNum--;}op.push(Symbol{reduceTerm.leftPart}); //把"E"push进符号栈,但还没和语义栈关联,下面进行curStatus = status.top();status.push(gotoTable[curStatus][VN2int[op.top().varName]]);//E->i规约,将E与语义栈栈顶值关联之后op.top().PLACE = ENTRY[semantic.top()]; //E.PLACE = ENTRY(i)}}else if (actionTable[curStatus][VT2int[symbolToRead]] == 10000){ //接受状态cout << "该表达式输入串能够被成功分析,acc!" << endl;status.pop();op.pop();status.pop();op.pop();}}
}//将四元式序列翻译为目标程序代码(汇编)
void translateToAssembly()
{cout << "—————————————四元式序列翻译为汇编指令序列———————————————————" << endl;for (int i = 0; i < formula.size(); i++){string op = formula[i].op;int arg1 = formula[i].arg1Index;int arg2 = formula[i].arg2Index;Symbol result = formula[i].result;if (op == "="){cout << "MOV R0," << symbolTable[arg1].varName << endl;cout << "MOV " << result.varName << ",R0" << endl;}else if (op == "@"){cout << "MOV R0," << symbolTable[arg1].varName << endl;cout << "NEG R0" << endl;cout << "MOV " << result.varName << ",R0" << endl;}else if (op == "+"){cout << "MOV R0," << symbolTable[arg1].varName << endl;cout << "ADD R0," << symbolTable[arg2].varName << endl;cout << "MOV " << result.varName << " R0" << endl;}else if (op == "-"){cout << "MOV R0," << symbolTable[arg1].varName << endl;cout << "SUB R0," << symbolTable[arg2].varName << endl;cout << "MOV " << result.varName << " R0" << endl;}else if (op == "*"){cout << "MOV AL," << symbolTable[arg1].varName << endl;cout << "MOV BL," << symbolTable[arg2].varName << endl;cout << "MUL BL" << endl;cout << "MOV " << result.varName << ",AX" << endl;}else if (op == "/"){cout << "MOV AX," << symbolTable[arg1].varName << endl;cout << "MOV BH," << symbolTable[arg2].varName << endl;cout << "DIV BH" << endl; //除法运算后,AH余数,AL商cout << "MOV " << result.varName << ",AL" << endl;}}
}int main()
{initGrammar(); //初始化文法//VT2int["$"] = 0; //文法中没有$符号,人为增加该终结符readVnAndVt();        //读取文法中所有的VN和VTconverge();           //构造first和follow集constructStatusSet(); //构造LR(1)分析表string code;ifstream myfile("ex4Data.txt");cout << "—————————————词法分析———————————————————" << endl;while (getline(myfile, code)) //按行读取文件,可读取空格scanner(code);            //词法分析结束,分析结果存储在lexicalTable中translate();                  //赋值表达式源程序翻译为四元式序列translateToAssembly();        //将四元式序列翻译为汇编代码return 0;
}

C++实现的利用LR(1)分析表对赋值表达式进行语法制导翻译生成四元式及汇编代码相关推荐

  1. LR(1)分析表-语法树-四元式

    这学期的编译原理终于学完了,不愧是号称最难的科目.要用C++从头到尾实现一下小型编译器,还真不容易啊.不过总算是做完了. 首先上文法,这个文法是根据上一篇博客简化的,但还是有一点问题的,暂时发现有一个 ...

  2. [编译原理]DO-WHILE循环语句的翻译程序设计(LR(1)方法、输出四元式)C++实现

    题目: DO-WHILE循环语句的翻译程序设计(LR(1)方法.输出四元式) 1 课设任务概述 初始条件: ​ 理论:完成编译原理,数据结构.高级编程语言.汇编语言等相关课程的学习,基于计算机专业知识 ...

  3. LR(0)分析表的构建

    LR(0)分析表的构建 一.实验要求 构建LR(0)分析表 例: G[E]: E->aA E->bB A->cA A->d B->cB B->d 二.实验原理 在网 ...

  4. 【编译原理笔记06】语法分析,移入-归约分析:自底向上的分析,LR(0)分析法,LR(0)分析表的构建(基于自动机)

    本次笔记内容: 4-8 自底向上的分析概述 4-9 LR分析法概述 4-10 LR0分析 4-11 LR0分析表构造 本节课幻灯片,见于我的 GitHub 仓库:第6讲 语法分析_3.pdf 本节课介 ...

  5. C++实现LR(1)分析表的构造

    构造LR(1)分析表的算法参考了龙书本科教学版: 龙书给的例子:(1)S′→S(2)S→CC(3)C→cC∣d\begin{aligned} &(1) S' \rightarrow S \\ ...

  6. LR(0)项目集规范族的构造及LR(0)分析表的构造

    求出文法的所有项目,按一定规则构造识别活前缀的NFA, 再确定化为DFA确定化的工作量较大,而且容易出错,实际应用中并不使用,这里介绍的目的仅仅是为了便于理解.具体见识别活前缀的有限自动机构建方法_用 ...

  7. 【编译原理】 LR(0) 分析表

    LR(0) 步骤 1. 写成 拓广文法 (S'→ S) 2. 活前缀的 DFA(靠近.后面的非终结符) 看状态Ii里面,是不是只存在一个规约项目.如果有两个规约项目,就是规约--规约冲突:如果同时有规 ...

  8. 【编译原理笔记09】语法制导翻译:语法制导翻译方案,在非递归的预测分析过程中进行翻译

    本次笔记内容: 5-5 语法制导翻译方案 5-6 在非递归的预测分析过程中进行翻译 本节课幻灯片,见于我的 GitHub 仓库:第9讲 语法制导翻译_2 文章目录 语法制导翻译方案 语法制导翻译方案 ...

  9. LR(0)语法制导翻译

    LR(0)语法制导翻译

最新文章

  1. linux怎么安装java环境变量_如何简单的在linux上安装jdk并配置环境变量
  2. Toward perfect reads: self-correction of short reads via mapping on de Bruijn graphs
  3. 干货丨 简述迁移学习在深度学习中的应用
  4. linux修改密码和宽限天数,Linux chage用法详解:修改用户密码状态
  5. UOJ#77. A+B Problem [可持久化线段树优化建边 最小割]
  6. python书籍排行榜前十名_学习Python,这些书你看过几本?
  7. 你搞清楚「NULL」、「0」、「'0'」、「0」「\0」了吗?
  8. sdp ddp内存怎么分_旗舰手机跑分66万+,缩短与PC差距,手机成生产力工具也许不是梦...
  9. Hive 导数据到本地(2种方式)
  10. CVPR 2020 |商汤提出应对尺度变化的目标检测新算法
  11. 5.过滤器作为模板——1D 相关、Matlab互相关实战_1
  12. spring-data-redis和jedis版本对应问题
  13. C++-实现日志log功能
  14. git 查看某些文档的历史版本_10分钟了解git
  15. 万字长文带你从头构建文本分类器
  16. din字体是开源字体吗_字体 DIN 与工业标准
  17. 关于spring boot的web.xml
  18. 趣头条自媒体审核不过怎么办,趣头条伪原创工具教程
  19. Photoshop设计精讲精练(读书笔记)
  20. 手把手教你搭建最新国产开源网络安全渗透测试集成靶场vulfocus

热门文章

  1. 数据为王,聚数学院引领大数据新时代
  2. springboot实现反向代理
  3. cisco设备接口下配置encapsulation dot1q vlan-id的作用
  4. html中创建学生对象,在考生文件夹下,存在一个数据库文件“sampl.mdb”。在数据库文件中已经建立了一个表对象“学生基本情...
  5. C#压缩或解压(rar和zip文件)
  6. 做好准备:独立游戏开发人员适用的 4P 营销理论
  7. Codeforces Round #616 (Div. 2)B. Array Sharpening
  8. android下运行时动态链接dlopen()和dlsym()的实现
  9. 编写 SQL 查询表格,按创建时间降序排列。
  10. mysql查询汉字拼音首字母_MySQL查询汉字的拼音首字母实例教程