-
2018-12-18 19:39:14
所有的源码:https://github.com/yanguojun123/Compile
先上代码:
(其余后面完善)
#pragma once #include<iostream> #include<string> #include <fstream> #include <sstream> #include<Windows.h> #include "tree.h" #include<stack> bool success = 1; using namespace std; char ch;//字符变量,存放最新读进的源程序字符 char strToken[100];//字符数组,存放构成单词符号的字符串 int len = 0;//记录字符串的长度 string klabel[29] = { "+","-","*","/","=","#","<","<=",">",">=",",",";",":=","(",")",".","const","var","procedure","begin","end","odd","if","then","call" ,"while","do","read","write" }; string slabel[100] = {}; string clabel[100] = {}; string result[1000] = {};//保存所有单词的结果数组 int procedureId = 0;//记录当前的过程层数 int tableId = 0;//当前名字表的下标 int dx = 3;//当前层数的偏移地址 int ip = 0;//全局符号表的指针 int slen = 0;//标识符表的下标 int clen = 0;//常量表的下标 //判断是否为数字 const char *input; int index = 0; int codeId = 0;//代码的下标 bool isDigit() { if (ch < 58 && ch >= 48) return true; else return false; } //判断是否为小写字母 bool issLetter() { if (ch <= 122 && ch >= 97) return true; else return false; } bool isDigit(char ch1) { if (ch1 < 58 && ch1 >= 48) return true; else return false; } //把字符串转化为数字 int strToint(string str) { int len = str.length(); int count = 0; for (int i = 0; i < len; i++) { if (str.at(i) <= 57 && str.at(i) >= 48) count = count + (str.at(i) - 48)*pow(10, len - i - 1); else return -1; } return count; } //把数字转化为字符串 //string intTostr(int num) //{ //} //判断是否为小写字母 bool issLetter(char ch1) { if (ch1 <= 122 && ch1 >= 97) return true; else return false; } //判断是否为大写字母 bool islLetter() { if (ch <= 90 && ch >= 65) return true; else return false; } //将下一输入字符读到ch中 void GetChar() { ch = input[index]; index++; } //判断ch中是否是空白,若是,则调用GetChar直至读入下一个非空白的字符 void GetBC() { while (ch == 32) GetChar(); } //将ch中的字符连接到strToken之后 void concat() { strToken[len] = ch; len++; } //对strToken中的字符串查找保留字表,若他是一个保留字则返回则返回他的编码,否则返回0值 int Reserve() { for (int i = 0; i < 29; i++) { /*const char *p = klabel[i].data(); if (strcmp(p,strToken)==0) { return i; }*/ if (klabel[i] == strToken) return i; } return -1; } //将搜索指示器回调一个字符位置 void Retract() { index--; ch = 32; } //将strToken中的标识符插入到符号表 int insertId() { slabel[slen] = strToken; slen++; return slen - 1; } //将strToken中的常数插入到常数表 int insertConst() { clabel[clen] = strToken; clen++; return clen - 1; } string readFileIntoString(char * filename) { ifstream ifile(filename); //将文件读入到ostringstream对象buf中 ostringstream buf; char ch; while (buf&&ifile.get(ch)) buf.put(ch); //返回与流对象buf关联的字符串 return buf.str(); } //检测是否已经存在此标识符 int isexists(string str) { for (int i = 0; i < slen; i++) if (str == slabel[i]) return 1; return 0; } //检测是否已经存在此常量 int isexistc(string con) { for (int i = 0; i < clen; i++) if (con == clabel[i]) return 1; return -1; } int isexists() { for (int i = 0; i < slen; i++) if (strToken == slabel[i]) return i; return -1; } //检测是否已经存在此常量 int isexistc() { for (int i = 0; i < clen; i++) if (strToken == clabel[i]) return i; return -1; } //名字表的结构体 struct symble { string name; string kind; int addr; int attribute;//val/value }symlabel; //判断是否退出 symble table[20]; //在符号表里查找某个标识符 int findSymble(string str) { for (int i = 0; i < tableId; i++) { if (table[i].name == str) return i; } return -1; } //在符号表里根据地址查找变量的名字 string findSymble(int addr1) { for (int i = 0; i < tableId; i++) { if (table[i].addr == addr1) return table[i].name; } return ""; } //目标指令的结构体: struct tarInstruc { string funcCode=" "; int levelDiff = 0; int displacement = 0; string content = " "; }; tarInstruc code[200]; //从关键字表查找关键字的下标 int findKlabel(string str) { for (int i = 0; i < 29; i++) { if (str == klabel[i]) return i+1; } return -1; } //添加code,运算类型 void codeAdd(string str,int lev,int place,string con) { code[codeId].funcCode = str; code[codeId].levelDiff = lev; code[codeId].displacement = place; code[codeId].content = con; codeId++; } //添加code,非运算 void codeAdd(string str, int lev, int place) { code[codeId].funcCode = str; code[codeId].levelDiff = lev; code[codeId].displacement = place; codeId++; } //主程序 void lex(string file1) { int code, value, num = 0; /*cout << "请输入单词长度"<<endl; cin >> num; cout << "请输入单词:"<<endl; cin >> input;*/ //char filename[] = "test.txt"; //const char *file = readFileIntoString(filename).data(); std::ifstream in(file1); std::ostringstream tmp; tmp << in.rdbuf(); std::string str = tmp.str(); cout << str << endl; for (int i = 0; i < str.length(); i++)//如果输入中有大写字母,则转换为小写字母 if (str.at(i) <= 90 && str.at(i) >= 65) str.at(i) = str.at(i) + 32; const char *file = str.data(); input = file; while (input[index] != 0) { len = 0; //strcpy(strToken,""); memset(strToken, 0, sizeof(strToken)); //cout << strToken << endl; //Sleep(1000); GetChar(); GetBC(); if (issLetter())//判断是否是字母 { while (issLetter() || isDigit()) { concat(); GetChar(); } Retract(); result[ip] = strToken; ip++; code = Reserve(); if (code == -1)//不在关键字表里,即为标识符 { int index1 = isexists();//检测此标识符是否存在 if (index1 != -1) cout << "(" << strToken << ",id," << index1 << ")" << endl; else { value = insertId(); cout << "(" << strToken << ",id," << value << ")" << endl;//输出标识符的三元组 }//cout << strToken<<endl; } else { cout << "(" << klabel[code] << "," << klabel[code] << ",-)" << endl;//输出关键字的二元组 } } else if (isDigit())//如果是数字,即为常量 { while (isDigit()) { concat(); GetChar(); } Retract(); result[ip] = strToken; ip++; int index2 = isexistc(); if (index2 != -1) cout << "(" << strToken << ",int," << index2 << ")" << endl; else { value = insertConst(); cout << "(" << strToken << ",int," << value << ")" << endl; } } /*else if (islLetter()) { while(islLetter()) { concat(); GetChar(); } Retract(); code = Reserve(); if (code == -1) cout << "拼写错误"<<endl; else cout << "(" << code << ",-)" << endl;//输出关键字的二元组 }*/ else//其余情况 { switch (ch) { case '+': cout << "(+,+," << "-)" << endl; result[ip] = "+"; ip++; break; case '-': cout << "(-,-," << "-)" << endl; result[ip] = "-"; ip++; break; case '*': cout << "(*,*," << "-)" << endl; result[ip] = "*"; ip++; break; case '/': cout << "(/,/," << "-)" << endl; result[ip] = "/"; ip++; break; case '=': cout << "(=,=," << "-)" << endl; result[ip] = "="; ip++; break; case '#': cout << "(#,#," << "-)" << endl; result[ip] = "#"; ip++; break; case '<': GetChar(); if (ch == '=') { cout << "(<=,<=," << "-)" << endl; result[ip] = "<="; ip++; } else { Retract(); cout << "(<,<," << "-)" << endl; result[ip] = "<"; ip++; } break; case '>': GetChar(); if (ch == '=') { cout << "(>=,>=," << "-)" << endl; result[ip] = ">="; ip++; } else { Retract(); cout << "(>,>," << "-)" << endl; result[ip] = ">"; ip++; } break; case ',': cout << "(,,,," << "-)" << endl; result[ip] = ","; ip++; break; case ';': cout << "(;,;," << "-)" << endl; result[ip] = ";"; ip++; break; case ':': GetChar(); if (ch == '=') { cout << "(:=,:=," << "-)" << endl; result[ip] = ":="; ip++; } else { Retract(); cout << "(:,:," << "-)" << endl; result[ip] = ":"; ip++; } break; case '(': cout << "((,(," << "-)" << endl; result[ip] = "("; ip++; break; case ')': cout << "(),)," << "-)" << endl; result[ip] = ")"; ip++; break; case '.': cout << "(.,.," << "-)" << endl; result[ip] = "."; ip++; break; case 10://排除掉换行符 break; default: cout << "拼写错误:" << ch << endl; break; } } } } //函数声明 void subProgram(treeNode<string> *tN); void conExplain(treeNode<string> *tN); void varExplain(treeNode<string> *tN); void processExplain(treeNode<string> *tN); void constDef(treeNode<string> *tN); void statement(treeNode<string> *tN); void varExplain(treeNode<string> *tN); void id(treeNode<string> *tN); void unsInt(treeNode<string> *tN); void dig(treeNode<string> *tN,int index); void processHead(treeNode<string> *tN); void AssignmentStatement(treeNode<string> *tN); void expression(treeNode<string> *tN); void CompoundStatement(treeNode<string> *tN); void conditions(treeNode<string> *tN); void AddAndSubtract(treeNode<string> *tN); void item(treeNode<string> *tN); void factor(treeNode<string> *tN); void MULAndDIV(treeNode<string> *tN); void ConditionStatement(treeNode<string> *tN); void relationship(treeNode<string> *tN); void processCall(treeNode<string> *tN); void readStatement(treeNode<string> *tN); void dowhile(treeNode<string> *tN); void writeStatement(treeNode<string> *tN); void letter(treeNode<string> *tN,int index); void digit(treeNode<string> *tN,int index); treeNode<string> *Tprogram=new treeNode<string>(2,"<程序>"); /*treeNode<string> *TsubProgram=new treeNode<string>(4,"<分程序>"); treeNode<string> *TconExplain = new treeNode<string>("<常量说明部分>"); treeNode<string> *TvarExplain = new treeNode<string>("<变量说明部分>"); treeNode<string> *TprocessExplain = new treeNode<string>("<过程说明部分>"); treeNode<string> *Tstatement = new treeNode<string>(1,"<语句>"); treeNode<string> *TconstDef = new treeNode<string>(3,"<常量定义>"); treeNode<string> *TunsInt = new treeNode<string>("<无符号整数>"); treeNode<string> *Tpoint = new treeNode<string>("."); treeNode<string> *TprocessHead = new treeNode<string>(3,"过程首部"); treeNode<string> *Tid = new treeNode<string>("标识符"); */ void program()//程序 { codeAdd("jmp", 0, -1);//暂时填一个 ip = 0; treeNode<string> *TsubProgram = new treeNode<string>(4,"<分程序>"); subProgram(TsubProgram); if (result[ip] == ".") { Tprogram->child[0] = TsubProgram; Tprogram->child[1] = new treeNode<string>("."); //**************目标代码的生成,最后的退出 codeAdd("opr", 0, 0,"return"); //************* cout << "成功"; } else exit(0); } void subProgram(treeNode<string> *tN)//分程序 { int count = 4; int tempTableId = tableId-1; //常量说明部分 if (result[ip] == "const") { treeNode<string> *TconExplain = new treeNode<string>("<常量说明部分>"); conExplain(TconExplain); count++; tN->child[0] = TconExplain; } //变量说明部分 if (result[ip] == "var") { treeNode<string> *TvarExplain = new treeNode<string>("<变量说明部分>"); varExplain(TvarExplain); count++; tN->child[1] = TvarExplain; } //过程说明部分 if (result[ip] == "procedure") { treeNode<string> *TprocessExplain = new treeNode<string>("<过程说明部分>"); processExplain(TprocessExplain); count++; tN->child[2] = TprocessExplain; } if (table[tempTableId].kind == "proc") table[tempTableId].addr = codeId; //**************目标代码的生成,开辟地址空间 int varNumber = 0; for (int i = 0; i < tableId; i++) if (table[i].attribute == procedureId && table[i].kind == "var") varNumber++; codeAdd("int",0,varNumber+3); //************* treeNode<string> *Tstatement = new treeNode<string>(1,"<语句>"); //***************目标代码生成,直接跳转到主程序 if (procedureId == 0) code[0].displacement = codeId-1; //********************** statement(Tstatement);//语句 tN->child[3]=Tstatement; } void conExplain(treeNode<string> *tN)//常量说明部分 { if (result[ip] == "const") { ip++; tN->child[0] = new treeNode<string>("const"); treeNode<string> *TconstDef1 = new treeNode<string>(3, "常量定义"); tN->child[1] = TconstDef1; constDef(TconstDef1); int count = 0; while (result[ip] == ",") { count++;//树的孩子数 tN->child[2*count] = new treeNode<string>(","); treeNode<string> *TconstDef2 = new treeNode<string>(3,"常量定义"); tN->child[2*count+1] = TconstDef2; ip++; constDef(TconstDef2); } if (result[ip] == ";") { ip++; //增加树的结构 tN->child[2*count + 2] = new treeNode<string>(";"); } else exit(0); } else exit(0); } void varExplain(treeNode<string> *tN)//变量说明部分 { if (result[ip] == "var") { ip++; tN->child[0] = new treeNode<string>("var"); treeNode<string> *Tid1 = new treeNode<string>(3, "<标识符>"); tN->child[1] = Tid1; table[tableId].name = result[ip]; table[tableId].attribute = procedureId; table[tableId].addr = dx; table[tableId].kind = "var"; tableId++; dx++; id(Tid1); int count = 0; while (result[ip] == ",") { ip++; count++; tN->child[2 * count] = new treeNode<string>(","); treeNode<string> *Tid2 = new treeNode<string>(3, "<标识符>"); tN->child[2 * count + 1] = Tid2; table[tableId].name = result[ip]; table[tableId].attribute = procedureId; table[tableId].addr = dx; table[tableId].kind = "var"; tableId++; dx++; id(Tid2); } if (result[ip] == ";") { ip++; tN->child[count + 1] = new treeNode<string>(";"); } else exit(0); } else exit(0); } void processExplain(treeNode<string> *tN)//过程说明部分 { procedureId++;//层数加1 dx = 3;//当前层数内地址变为1 treeNode<string> *TprocessHead = new treeNode<string>(3,"<过程首部>"); tN->child[0] = TprocessHead; treeNode<string> *TsubProgram = new treeNode<string>( "<分程序>"); tN->child[1] = TsubProgram; processHead(TprocessHead); subProgram(TsubProgram); if (result[ip] == ";") { tN->child[2] = new treeNode<string>(";"); //**************目标代码的生成,过程说明结束 codeAdd("opr", 0, 0,"return"); //************* procedureId--; ip++; int count=0; while (result[ip]=="procedure") { count++; treeNode<string> *TprocessExplain = new treeNode<string>("<过程说明部分>"); tN->child[count + 2] = TprocessExplain; processExplain(TprocessExplain); } } else exit(0); } void statement(treeNode<string> *tN)//语句 { if (isexists(result[ip]))//赋值语句 { treeNode<string> *TAssignmentStatement = new treeNode<string>(3,"<赋值语句>"); tN->child[0] = TAssignmentStatement; AssignmentStatement(TAssignmentStatement); } else if (result[ip] == "if")//条件语句 { treeNode<string> *TConditionStatement = new treeNode<string>(3,"<条件语句>"); tN->child[0] = TConditionStatement; ConditionStatement(TConditionStatement); } else if (result[ip] == "while")//当型循环 { treeNode<string> *Tdowhile = new treeNode<string>(3,"<当型循环语句>"); tN->child[0] = Tdowhile; dowhile(Tdowhile); } else if (result[ip] == "call")//过程调用 { treeNode<string> *Tcall= new treeNode<string>(2, "<过程调用语句>"); tN->child[0] = Tcall; processCall(Tcall); } else if (result[ip] == "read")//读语句 { treeNode<string> *Tread = new treeNode<string>(2, "<读语句>"); tN->child[0] = Tread; readStatement(Tread); } else if (result[ip] == "write")//写语句 { treeNode<string> *Twrite = new treeNode<string>(2, "<写语句>"); tN->child[0] = Twrite; writeStatement(Twrite); } else if (result[ip] == "begin")//复合语句 { treeNode<string> *TCompoundStatement = new treeNode<string>(2, "<复合语句>"); tN->child[0] = TCompoundStatement; CompoundStatement(TCompoundStatement); } } void constDef(treeNode<string> *tN)//常量定义 { treeNode<string> *Tid = new treeNode<string>( "<标识符>"); tN->child[0] = Tid; table[tableId].name = result[ip]; table[tableId].kind = "const"; id(Tid); if (result[ip] == "=") { tN->child[1] = new treeNode<string>("="); ip++; treeNode<string> *TunsInt = new treeNode<string>("<无符号整数>"); tN->child[2] = TunsInt; table[tableId].attribute = strToint(result[ip]); tableId++; unsInt(TunsInt); } else exit(0); } void id(treeNode<string> *tN)//标识符 { /*if (isexists(result[ip])) { tN->child[0] = new treeNode<string>(result[ip]); ip++; } else exit(0); */ int index=0; treeNode<string> *Tletter1 = new treeNode<string>("<字母>"); tN->child[0] = Tletter1; letter(Tletter1,0); index++; int max = result[ip].length(); for (index=1; index < max && ((result[ip].at(index) >= 97 && result[ip].at(index) <= 122) || (result[ip].at(index) >= 48 && result[ip].at(index) <= 57)); index++) { if (result[ip].at(index) >= 97 && result[ip].at(index) <= 122) { treeNode<string> *Tletter2 = new treeNode<string>("<字母>"); tN->child[index] = Tletter2; letter(Tletter2, index); } else { treeNode<string> *Tdig = new treeNode<string>("<数字>"); tN->child[index] = Tdig; dig(Tdig, index); } } ip++; } void unsInt(treeNode<string> *tN)//无符号整数 { /*if (isexistc(result[ip])) { tN->child[0] = new treeNode<string>(result[ip]); ip++; } else exit(0);*/ int index = 0; treeNode<string> *Tdig1 = new treeNode<string>("<数字>"); tN->child[0] = Tdig1; dig(Tdig1, 0); index++; int max = result[ip].length(); for (index = 1; index < max && (result[ip].at(index) >= 48 && result[ip].at(index) <= 57); index++) { if (result[ip].at(index) >= 48 && result[ip].at(index) <= 57) { treeNode<string> *Tdig2 = new treeNode<string>("<数字>"); tN->child[index] = Tdig2; dig(Tdig2, index); } } ip++; } void letter(treeNode<string> *tN,int index1) { if (result[ip].at(index1) >= 97 && result[ip].at(index1) <= 122) { string str; stringstream stream; stream << result[ip].at(index1); str = stream.str();//将char转换为string tN->child[0] = new treeNode<string>(str); } else exit(0); } void dig(treeNode<string> *tN,int index)//数字 { if (result[ip].at(index) <= 57 && result[ip].at(index) >= 48) { string str; stringstream stream; stream << result[ip].at(index); str = stream.str();//将char转换为string tN->child[0] = new treeNode<string>(str); } else exit(0); } void processHead(treeNode<string> *tN)//过程首部 { if (result[ip] == "procedure") { ip++; tN->child[0] = new treeNode<string>("procedure"); treeNode<string> *Tid = new treeNode<string>("<标识符>"); tN->child[1] = Tid; /******/ table[tableId].kind = "proc"; table[tableId].name = result[ip]; table[tableId].addr = codeId; table[tableId].attribute = procedureId-1; tableId++; id(Tid); /****************/ if (result[ip] == ";") { ip++; tN->child[1] = new treeNode<string>(";"); } else exit(0); } else exit(0); } void AssignmentStatement(treeNode<string> *tN)//赋值语句 { treeNode<string> *Tid = new treeNode<string>("<标识符>"); tN->child[0] = Tid; int tempIp = ip;//暂存ip id(Tid); if (result[ip] == ":=") { ip++; tN->child[1] = new treeNode<string>(":="); treeNode<string> *Texpression = new treeNode<string>("<表达式>"); tN->child[3] = Texpression; expression(Texpression); //**************目标代码的生成,赋值语句 int tableIndex = findSymble(result[tempIp]); if (tableIndex == -1) { cout << "此变量未定义" << endl; exit(0); } codeAdd("sto", abs(table[tableIndex].attribute - procedureId), table[tableIndex].addr); //************* } else exit(0); } void expression(treeNode<string> *tN)//表达式 { if (result[ip] == "+" || result[ip] == "-") { ip++; tN->child[0] = new treeNode<string>(result[ip]); } treeNode<string> *Titem = new treeNode<string>("<项>"); tN->child[1]=Titem; item(Titem); int count = 0; while (result[ip] == "+" || result[ip] == "-") { count++; treeNode<string> *TAddAndSubtract = new treeNode<string>("<加减运算符>"); tN->child[2*count] = TAddAndSubtract; treeNode<string> *Titem = new treeNode<string>("<项>"); tN->child[2 * count+1] = Titem; int tempIp = ip;//暂存Ip AddAndSubtract(TAddAndSubtract); item(Titem); //**************目标代码的生成,加减运算 codeAdd("opr", 0, findKlabel(result[tempIp]), result[tempIp]); //************* } } void CompoundStatement(treeNode<string> *tN)//复合语句 { if (result[ip] == "begin") { tN->child[0] = new treeNode<string>("begin"); ip++; treeNode<string> *Tstatement1 = new treeNode<string>("<语句>"); tN->child[1] = Tstatement1; statement(Tstatement1); int count = 0; while (result[ip] == ";") { ip++; count++; tN->child[2 * count] = new treeNode<string>(";"); treeNode<string> *Tstatement2 = new treeNode<string>("<语句>"); tN->child[2 * count + 1] = Tstatement2; statement(Tstatement2); } if (result[ip] == "end") { tN->child[2 * count+2] = new treeNode<string>("end"); ip++; } else exit(0); } else exit(0); } void conditions(treeNode<string> *tN)//条件 { if (result[ip] == "odd") { ip++; tN->child[0] =new treeNode<string>("odd"); treeNode<string> *Texpression = new treeNode<string>("<表达式>"); expression(Texpression);tN->child[1] = Texpression; //***********目标代码生成,odd运算 codeAdd("opr",0,findKlabel("odd"),"odd"); // } else { treeNode<string> *Texpression1 = new treeNode<string>("<表达式>"); tN->child[0] = Texpression1; expression(Texpression1); treeNode<string> *Trealationship = new treeNode<string>("<关系运算符>"); tN->child[1] = Trealationship; int tempIp = ip;//保存ip relationship(Trealationship); treeNode<string> *Texpression2 = new treeNode<string>("<表达式>"); tN->child[2] = Texpression2; expression(Texpression2); //**************目标代码的生成,加减运算 codeAdd("opr", 0, findKlabel(result[tempIp]), result[tempIp]); //************* } } void item(treeNode<string> *tN)//项 { treeNode<string> *Tfactor1 = new treeNode<string>("<因子>"); tN->child[0] = Tfactor1; factor(Tfactor1); int count = 0; while (result[ip]=="*"|| result[ip] == "/") { count++; treeNode<string> *TMULAndDIV = new treeNode<string>("<乘除运算符>"); tN->child[2*count-1] = TMULAndDIV; int tempIp = ip;//暂存Ip MULAndDIV(TMULAndDIV); treeNode<string> *Tfactor2 = new treeNode<string>("<因子>"); tN->child[2*count] = Tfactor2; factor(Tfactor2); //**************目标代码的生成,加减运算 codeAdd("opr", 0, findKlabel(result[tempIp]), result[tempIp]); //************* } } void factor(treeNode<string> *tN)//因子 { if ((result[ip].at(0) <= 122 && result[ip].at(0) >= 97)) { treeNode<string> *Tid = new treeNode<string>("<标识符>"); tN->child[0] = Tid; //*********判断标识符为变量还是常量 int tableIndex = findSymble(result[ip]); if (tableIndex != -1) { if (table[tableIndex].kind == "const") { codeAdd("lit", 0, table[tableIndex].attribute); } else if (table[tableIndex].kind == "var") { codeAdd("lod", abs(table[tableIndex].attribute - procedureId), table[tableIndex].addr); } } //****************/ id(Tid); } else if ((result[ip].at(0) <= 57 && result[ip].at(0) >= 48)) { treeNode<string> *TunsInt = new treeNode<string>("<无符号整数>"); tN->child[0] = TunsInt; //****************目标代码生成,常数 codeAdd("lit",0,strToint(result[ip])); // unsInt(TunsInt); } else if ((result[ip] == "(")) { tN->child[0] = new treeNode<string>("("); treeNode<string> *Texpression = new treeNode<string>("<表达式>"); tN->child[1] = Texpression; expression(Texpression); if (result[ip] == ")") { tN->child[2] = new treeNode<string>(")"); ip++; } else exit(0); } else exit(0); } void AddAndSubtract(treeNode<string> *tN)//加减运算符 { if (result[ip] == "+" || result[ip] == "-") { tN->child[0] = new treeNode<string>(result[ip]); ip++; } else exit(0); } void MULAndDIV(treeNode<string> *tN)//乘除运算符 { if (result[ip] == "*" || result[ip] == "/") { tN->child[0] = new treeNode<string>(result[ip]); ip++; } else exit(0); } void relationship(treeNode<string> *tN)//关系运算符 { if (result[ip] == "=" || result[ip] == "#"||result[ip]=="<"|| result[ip] == "<="||result[ip] == ">" ||result[ip] == ">=") { tN->child[0] = new treeNode<string>(result[ip]); ip++; } else exit(0); } void ConditionStatement(treeNode<string> *tN)//条件语句 { if (result[ip] == "if") { tN->child[0] = new treeNode<string>("if"); ip++; treeNode<string> *Tconditions = new treeNode<string>("<条件>"); tN->child[1] = Tconditions; conditions(Tconditions); //**************目标代码的生成,非真则跳转 codeAdd("jpc", 0, 0);//暂时先填着地址0 int tempId = codeId - 1; //************* if (result[ip] == "then") { ip++; tN->child[0] = new treeNode<string>("then"); treeNode<string> *Tstatement = new treeNode<string>("<语句>"); tN->child[1] = Tstatement; statement(Tstatement); //回填之前的jpc code[tempId].displacement = codeId; //************* } else exit(0); } else exit(0); } void processCall(treeNode<string> *tN)//过程调用语句 { if (result[ip] == "call") { ip++; treeNode<string> *Tid = new treeNode<string>("<标识符>"); tN->child[0] = Tid; //****************目标代码生成,过程调用 int tempAddr = 0; int tempId = 0; for (int i = 0; i < tableId; i++) { if (table[i].name == result[ip]) { tempAddr = table[i].addr; tempId = i; break; } } codeAdd("cal",abs(procedureId-table[tempId].attribute),tempAddr); //**********************************8 id(Tid); } else exit(0); } void dowhile(treeNode<string> *tN)//当型循环 { if (result[ip] == "while") { tN->child[0] = new treeNode<string>("while"); ip++; int tempAddr = codeId+1;//while循环的入口地址 treeNode<string> *Tconditions = new treeNode<string>("<条件>"); tN->child[1] = Tconditions; conditions(Tconditions); //**************目标代码的生成,非真则跳转 codeAdd("jpc", 0, 0);//暂时先填着地址0 int tempId = codeId-1; //************* if (result[ip] == "do") { tN->child[2] = new treeNode<string>("do"); ip++; treeNode<string> *Tstatement = new treeNode<string>("<语句>"); tN->child[3] = Tstatement; statement(Tstatement); //**************目标代码的生成,无条件跳转 codeAdd("jmp", 0, tempAddr); //回填之前的jpc code[tempId].displacement = codeId; //************* } else success = 0; } else exit(0); } void readStatement(treeNode<string> *tN)//读语句 { if (result[ip] == "read") { tN->child[0] = new treeNode<string>("read"); //**************目标代码的生成,读语句 codeAdd("opr", 0, findKlabel(result[ip]), result[ip]); //************* ip++; if (result[ip] == "(") { tN->child[1] = new treeNode<string>("("); ip++; treeNode<string> *Tid1 = new treeNode<string>("<标识符>"); tN->child[2] = Tid1; //*******************目标代码的生成,结果的传递 int tableIndex = findSymble(result[ip]); if (tableIndex == -1) { cout << "未定义此变量" << endl; exit(0); } codeAdd("sto", abs(table[tableIndex].attribute - procedureId), table[tableIndex].addr); //******************** id(Tid1); int count = 0; while (result[ip] == ",") { count++; tN->child[2*count+1] = new treeNode<string>(","); ip++; //**************目标代码的生成,读语句 codeAdd("opr", 0, findKlabel("read"), "read"); //************* treeNode<string> *Tid2 = new treeNode<string>("<标识符>"); tN->child[2*count+2] = Tid2; //*******************目标代码的生成,结果的传递 tableIndex = findSymble(result[ip]); codeAdd("sto", 0, table[tableIndex].addr); //******************** id(Tid2); } if (result[ip] == ")") { tN->child[2*count+3] = new treeNode<string>(")"); ip++; } else exit(0); } else exit(0); } else exit(0); } void writeStatement(treeNode<string> *tN)//写语句 { if (result[ip] == "write") { tN->child[0] = new treeNode<string>("write"); ip++; if (result[ip] == "(") { ip++; tN->child[1] = new treeNode<string>("("); treeNode<string> *Texpression1 = new treeNode<string>("<表达式>"); tN->child[2] = Texpression1; expression(Texpression1); //**************目标代码的生成,写语句 codeAdd("opr", 0, findKlabel("write"), "write"); //************* int count = 0; while (result[ip] == ",") { count++; ip++; tN->child[2 * count + 1] = new treeNode<string>(","); treeNode<string> *Texpression2 = new treeNode<string>("<表达式>"); tN->child[2 * count + 2] = Texpression2; expression(Texpression2); //**************目标代码的生成,写语句 codeAdd("opr", 0, findKlabel("write"), "write"); //************* } if (result[ip] == ")") { tN->child[2 * count + 3] = new treeNode<string>(")"); ip++; } else exit(0); } else exit(0); } else exit(0); }
更多相关内容 -
编译原理目标代码生成_编译原理中间代码形式
2020-07-17 11:34:45第 7 章 目标代码生成 (3) 对于变量 c 有 USE(c,B 2 )=2 LIVE(c,B 2 )=1 USE(c,B 3 )=1 LIVE(c,B 3 )=0 USE(c,B 4 )=1 LIVE(c,B 4 )=0 因此变量 c 在一次循环中执行代价的节省总数为 [USE(c,B)+ 2*LIVE(c,B)] B L =2... -
编译原理目标代码生成学习课程.pptx
2021-10-01 07:10:36编译原理目标代码生成学习课程.pptx -
编译原理目标代码生成.pptx
2020-04-16 01:06:30第1页/共73页7.1 一个简单代码生成器 我们首先介绍一个简单的代码生成器此生成器依次把每条中间代码变换成目标代码并且在一个基本块范围内考虑如何充分利用寄存器的问题一方面在基本块中当生成计算某变量值的目标... -
习题笔记:编译原理目标代码生成
2019-11-20 14:52:29 -
编译原理之代码生成
2017-12-18 16:13:41目标代码生成阶段的任务是:将此前的中间代码转换成特定机器上的机器语言或汇编语言,这种转换程序便被称为代码生成器。1. 程序移植性和编译器模块设计的关系 之所以将编译原理分成这种多阶段多模块的组织形式,...前面提到了经过了词法分析->语法分析->语义分析->中间代码优化,最后的阶段便是在目标机器上运行的目标代码的生成了。目标代码生成阶段的任务是:将此前的中间代码转换成特定机器上的机器语言或汇编语言,这种转换程序便被称为代码生成器。
1. 程序移植性和编译器模块设计的关系
之所以将编译原理分成这种多阶段多模块的组织形式,本质的考虑其实只有两个方面:
一、代码复用:尽可能在不增加程序员工作量的前提下,增加应用程序的可移植性。
( 可我们知道不同机器的机器指令集和硬件结构,千差万别,而前面又提到了为了将程序的执行效率提升到最大,显然是需要将软件按照硬件特性极尽可能地定制化优化,其实现在AI芯片的发展趋势也是这种思想的另一面体现。现今AI芯片为了加速深度学习为代码的超强度计算效率,出现了针对具体程序架构定制化芯片的需求,如CPU->GPU的发展,便是GPU迎合了深度学习单轮多次简单运算的需求,CPU->FPGA的矩阵运算侧重也是Facebook引领的另一硬件绑定具体软件计算需求的工程案例,而最为极端者莫过于当下Google推出的TPU计算芯片,完全剔除不必要的硬件设备,根据Google的深度学习Tensorflow架构定制化的计算芯片,更是以极致的定制化获取比CPU计算速度高200倍的显著成果。)。所以再一次验证了“银弹”理论,如果有问题解决不了,那就加一层抽象层了。所以提高代码移植性的集大成者Java,便是通过引入JVM将应用程序层和具体硬件层隔开。
图1. Java-多目标机
显然对于Java程序可以共享一套“词法分析+语法分析+语义分析+中间代码优化引擎”这一套前端套件,而针对不同机型的定制化目标代码生成器则可以通过官方渠道的支持和更新来组装成自己所需的后端套件组。这样便可以让程序员尽可能地有较多的自由编写的空间,极大地提升代码可移植性,而不像C++编写的DLL库,即便采用复杂的COM规则,极为小心地编写,但也可能因为编译器版本不同导致移植性不通过。二、特定机器的优化器和生成器复用:针对特定机器的目标代码生成和优化器的工作极为复杂精深,有一套成功的,当然要尽可能复用它。
由于代码生成阶段的目标代码和具体计算机的结构有关,如指令格式、字长以及寄存器的个数和种类,并与指令的语义和所用操作系统等都密切相关,特别是高级语言的语义功能复杂,并且计算机硬件结构多样性都给代码生成的理论研究带来很大的复杂性,因此实际实现起来是非常困难的。所以难得生成一款后端的代码生成器,当然是想让它可以独立出来,被多次组装参与其他编译器的生产过程。
图2. 多种语言-一种目标机型这种情况被称为定计算机情况:当限定某种计算机时,而高级语言为多种情况下所设计的中间语言,应能充分反映限定计算机的特点称MSIL(Machine Specific Intermediate language)。对这种机器的所有编译程序在分析阶段都生成MSIL,在实现一个编译程序时,尽量把编译过程的大量工作放在代码生成阶段,即MSIL到目标程序的翻译上,以减轻不同语言翻译的分析任务。因不管多少种高级语言,MSIL到目标程序的代码生成只需做一次即可。
当然也正是这种组织特性,让本来是集团作战的编译器生成工作,现如今变得不再是难以企及。同时也让各行各业根据自身需求和侧重点不同,甚至可以定制化自己的行业的专属语言(Domain Specific Language)变得可实现。
2. 代码生成的优化手段:寄存器分配
说了这么多,其实只需要明白代码生成器是结合目标机器平台定制化的一套后端套件,这也是为何业界的主流计算机都是按照x86、x64_86这些业界标准来设计的,如果你家公司另辟蹊径自己设计出一套硬件体系,即便你能设计生产出来,但你确定IT界会有下游供应商给你设计类似于代码生成器这种配套套件吗?衡量最终生成的目标代码的质量无非是从两个方面来进行评估:空间占用和运行效率,这其中涉及到诸多和具体硬件绑定的细节,大多数都属于难度高且并不通用的范畴。而寄存器的使用规则则是少数具有通用的手段,故而可以借分析寄存器分配来分析一下目标代码优化和生成过程。
Q: 为什么在代码生成时要考虑充分利用寄存器?
A: 因为当变量值存在寄存器时,引用的变量值可直接从寄存器中取,减少对内存的存取次数,这样便可提高运行速度。因此如何充分利用寄存器是提高目标代码运行效率的重要途径。Q: 寄存器分配的原则是什么?
A: (1)逻辑有效范围内尽量保留: 当生成某变量的目标代码时,尽量让变量的值或计算结果保留在寄存器中,直到寄存器不够分配时为止。
(2) 逻辑块出口处,和内存中的源数据同步:当到基本块出口时,将变量的值存放在内存中,因为一个基本块可能有多个后继结点或多个前驱结点,同一个变量名在不同前驱结点的基本块内出口前存放的R可能不同,或没有定值,所以应在出口前把寄存器的内容放在内存中,这样从基本块外入口的变量值都在内存中
(3) 及时释放,提升寄存器使用效率:对于在一个基本块内后边不再被引用的变量所占用的寄存器应尽早释放,以提高寄存器的利用效率。可以看到在进行缓存淘汰更新时我们采用了LRU策略,LRU策略是属于经典的“线性思维”–即过去常被使用的,在未来也会常被使用。而这里寄存器则不能采用“线性思维”,因为我们看自己的代码都知道,变量的使用虽然在局部范围还算符合“局部性原理”,但是稍微放宽到一定尺度上的变量集使用情况,则发现更多是无序的。所以在进行寄存器分配策略的研究上,只能比较粗暴点,事先将目标代码再次遍历一遍,将变量的使用情况事先整理好,并用所谓“待用信息链”的数据结构来保存每个变量的使用情况。这种策略并非LRU那种后视推导逻辑,而是耍赖的先知般论断逻辑,但是考虑到一旦将目标代码的寄存器使用效率最大化,则无疑是一劳永逸的,故而也是划算的。
变量的待用信息链计算方法
前面根据寄存器的使用原则可以看到,寄存器的分配是以基本块为单位的,因为基本块作为程序流的最小单元,存在着数据同步和异步的问题,故而在进行寄存器分配时,要审核的代码范围只需要涉及到当前基本块即可。首先为任一变量设置两个信息链:待用信息链和活跃变量信息链。
考虑到处理的方便,可假定对基本块中的变量在出口处都是活跃的,而对基本块内的临时变量可分为两种情况处理。
a) 一般情况下基本块内的临时变量在出口处都认为是不活跃的。
b) 如果中间代码生成时的算法允许某些临时变量在基本块外可以被引用时,则这些临时变量也是活跃的。
在基本块内计算变量的使用信息链(觉得采用栈式更符合这种信息链的更新情况),步骤如下:① 对各基本块的符号表中的”待用信息”栏和”活跃信息”栏置初值,即把”待用信息”栏置”非待用”,对”活跃信息”栏按在基本块出口处是否为活跃而置成”活跃”或”非活跃”。现假定变量都是活跃的,临时变量都是非活跃的。
② 倒着来从基本块出口到基本块入口由后向前依次处理每个四元式。对每个四元式i:A:=B op C,依次执行下述步骤:
a) 把符号表中变量A的待用信息和活跃信息附加到四元式i上。
b) 把符号表中变量A的待用信息栏和活跃信息栏分别置为 “非待用” 和 “非 活跃”。由于在i中对A的定值只能在i以后的四元式才能引用,因而对i以前的四元式来说A是不活跃也不可能是待用的。
c) 把符号表中B和C的待用信息和活跃信息附加到四元式i上。
d) 把符号表中B和C的待用信息栏置为”i”,活跃信息栏置为”活跃”。说的麻烦,举个例子就好了:
(1) T∶=A-B (2) U∶=A-C (3) V∶=T+U (4) D∶=V+U
加上信息链条之后,则标记情况如下
(1) T【(3)L】:= A【(2)L】 - B【FL】 (2) U【(3)L】:= A【FL】 - C【FL】 (3) V【(4)L】:= T【FF】 + U【(4)L】 (4) D【FL】:= V【FF】 + U【FF】
这样根据信息链表法,在每次运算到一个表达式时,如果寄存器数目不够,即无空余寄存器可用,则可以遍历一下当前在寄存器中的变量的待用信息链,然后选择接下来最远将被调用的变量释放其所占用寄存器,分配寄存器的算法为:
① 如果
B
的现行值在某寄存器Ri中,且该寄存器只包含B
的值,或者B
与A
是同一标识符,或B
在该四元式后不会再被引用,则可选取Ri
作为所需的寄存器R
,并转(4)
;
② 如果有尚未分配的寄存器,则从中选用一个Ri
为所需的寄存器R
,并转(4)
;
③ 从已分配的寄存器中选取一个Ri
作为所需寄存器R
,其选择原则为:占用该寄存器的变量值同时在主存中,或在基本块中引用的位置最远,这样对寄存器Ri
所含的变量和变量在主存中的情况必须先做如下调整:即对RVALUE[Ri]
中的每一变量M
,如果M
不是A
且AVALUE[M]
不包含M
,则需完成以下处理;
a) 生成目标代码ST Ri,M
即把不是A的变量值由Ri中送入内存中;
b) 如果M
不是B
,则令AVALUE[M]={M}
,否则,令AVALUE[M]={M, Ri}
;
c) 删除RVALUE[Ri]
中的M
;
④ 给出R
,返回。至此可以看到,单纯是寄存器分配便是需要较多数据结构配合和工作时间消耗的,管中窥豹,可以看到代码生成器的一个部件工作量便是很复杂的。
-
编译原理课程设计 目标代码生成器
2021-04-13 08:30:17代码生成器。它依次把每条中间代码变换成目标代码,并且在一个基本块范围内考虑如何充分利用寄存器的问题。 代码生成器。它依次把每条中间代码变换成目标代码,并且在一个基本块范围内考虑如何充分利用寄存器的问题... -
编译原理笔记【第十章目标代码生成】
2020-06-09 09:15:04文章目录第一节 目标代码生成概述1.1 目标代码生成的任务1.2 主要问题1.3 GAM第二节 简单代码生成2.1 x=y2.2 x=-y2.3 x=y+z2.4 转移语句第三节 寄存器分配3.1 合理分配寄存器3.2 变量的访问和回写3.3 寄存器分配实例...文章目录
第一节 目标代码生成概述
1.1 目标代码生成的任务
将中间代码翻译成等价的目标代码
输入:中间代码(三地址码)
输出:目标代码(汇编代码)1.2 主要问题
针对特定的目标计算机,目标代码生成需考虑的主要问题包括:
- 目标计算机的指令系统
- 目标计算机的寄存器分配
- 目标计算机的存储空间分配
1.3 GAM
第二节 简单代码生成
不涉及函数代码生成
复杂代码涉及
2.1 x=y
2.2 x=-y
2.3 x=y+z
2.4 转移语句
第三节 寄存器分配
3.1 合理分配寄存器
3.2 变量的访问和回写
3.3 寄存器分配实例
3.4 寄存器分配方法
第四节 存储空间分配
4.1 程序的存储空间
4.2 活动记录
4.3 参数传递
4.4 非局部变量
-
编译原理课程设计——目标代码生成器
2011-09-13 14:50:48学生在学习《编译原理》课程设计中,结合各章节的构造编译程序的基本理论,总共用一周的时间完成课程设计。要求用C或C++语言描述及上机调试,实现五个题目中任意一个,是学生将理论与实际应用结合其,起来,受到软件... -
编译原理(三)目标代码的生成与优化基本概念
2020-03-23 08:31:37前边产生中间代码之后,后边的事儿就交给了后端 -
编译原理(二十)——目标代码生成
2020-11-04 22:36:44一、目标代码 二、虚拟目标机的指令系统 三、虚拟目标机的寄存器 四、四元式转化为目标指令 五、多寄存器的分配 六、对目标程序的评价 -
编译原理——代码生成——目标机器.ppt
2022-02-27 09:51:22编译原理——代码生成——目标机器.ppt -
编译原理实验报告-目标代码的优化
2012-06-11 22:28:11东北大学编译原理实验报告,用编译语言实现目标代码的优化,有详细的代码 -
BIT-Minicc编译原理实验-MIPS汇编目标代码生成最傻瓜的思路+问题记录
2020-06-26 22:42:26编译原理课程实验要求为BIT-Minicc编译器开发目标代码生成部分,本文针对开发过程中的一些问题做记录,主要是寄存器分配和函数调用相关的问题。 中间代码 中间代码采用我之前在中间代码生成实验中编写的阉割版Maple ... -
东北大学编译原理课程设计源代码
2018-04-20 20:30:10东北大学编译原理课程设计源代码,供学弟学妹们参考。 (下载所需积分会随着下载量不断增加,积分要求太多了私信我,我重新发布) -
编译实验(三)目标代码生成
2018-01-28 17:00:09而代码生成则是通过四元式来完成。我们先从简单开始做起。 编译实验项目下载链接:http://download.csdn.net/download/supersmart_dong/10224159 例如四元式(j,0,0,7)这样的,代码生成只需要一个goto语句;(j=,A,B... -
编译原理之目标代码的生成和优化
2020-11-03 10:37:50文章目录目标代码生成正确的指令分配寄存器指令重排序LLVM 的实现Maximal Munch 算法 目标代码生成 一个正式的编译器后端,代码生成部分需要考虑得更加严密才可以。那么具体要考虑哪些问题呢?其实主要有三点: ... -
编译原理-中间代码生成
2019-04-17 10:43:52如果不生成中间代码而是直接生成机器语言或者汇编语言形式的目标代码,优点是编译时间短,缺点是目标代码执行效率和质量都比较低,移植性差。 1.2 表示形式 逆波兰式(后缀式)、三地址码(三元式、四元式)、... -
编译原理实验源码.zip
2020-12-07 21:15:23华中科技大学编译原理实验源码一到四,运行makefile文件即可,不过电脑应该先安装c编译器。 实验一:词法语法分析器的设计与实现; 实验二:符号表管和语义检查; 实验三:中间代码生成和优化...实验四:目标代码生成。 -
编译原理实验代码(四则表达式编译及生成汇编代码)
2011-11-28 16:36:56这是编译原理的实验,关于四则表达式的编译(词法、语法、语义分析,目标代码生成)。里面有实验指导书以及注释详细的源代码。详细请看博客: http://blog.csdn.net/touch_2011/article/details/7019163 -
编译原理与技术讲义 第10章 目标代码生成.ppt
2022-05-19 23:32:38编译原理与技术讲义 第10章 目标代码生成.ppt -
华中科技大学 编译原理 面向过程的C语言的编译器设计 含有词法分析和语法分析、语义分析、中间代码生成的 ...
2020-02-07 23:21:07华中科技大学 编译原理 面向过程的C语言的编译器设计 功能包括:词法分析和语法分析、语义分析、中间代码生成... 实验四:目标代码生成:在前三个实验的基础上实现目标代码生成。也可以使用工具如LLVM来生成目标代码。 -
编译原理:中间代码生成
2020-08-22 15:42:19(2)使编译程序改变目标机更容易;易于编译器的移植 (3)使编译程序的结构在逻辑上更为简单明确,以中间语言为界面,编译前端和后端的接口更清晰。 中间语言的形式:后缀式,图表示法,三元式 编译过程中... -
编译原理习题(含答案)——20代码生成——哈工大陈鄞配套版本
2018-06-14 11:57:55代码生成1 在目标代码生成阶段,符号表用于( )。A. 目标代码生成B. 语义检查C. 语法检查D. 地址分配 2 经编译得到的目标程序是( )。A. 机器语言程序或汇编语言程序B. 四元式序列C. 三元式序列D. 二元式序列 3 ( )... -
编译原理及实现技术:27.目标代码生成.ppt
2021-09-20 09:45:50编译原理及实现技术:27.目标代码生成.ppt -
编译原理 第十章 代码生成_四元式序列编译原理
2020-01-10 14:39:27第十章 代码生成 代码生成概述 构造代码...代码生成器 目标代码一般有三种形式 能够立即执行的机器语言代码所有地址均已定位 待装配的机器语言模块当需要执行时由连接装入程序把它们和某些运行程序连接起来转换成能执 -
编译原理 面向过程的C--语言的编译器设计 功能包括:词法分析和语法分析、语义分析、中间代码生成的 ...
2019-09-13 18:01:49华中科技大学 编译原理 面向过程的C--语言的编译器设计 功能包括:词法分析和语法分析、语义分析、中间代码生成的 源码.zip -
目标代码的三种形式 编译原理 输出目标代码的形式有哪些
2021-06-09 09:59:26目标代码有哪几种形式?生成目标代码时通常应考虑哪目标代码有哪几种形式?生成目标代码时通常应考虑哪几个问题?...(采用中间代码是把源程序映射成中间代码表示,再映射成目标代码的工作分在几个阶段进行,使编译...