还剩16页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
递归子程序算法int Proceduresifstream from_file{Indent;H HcoutS endlencil;子程序开始indentation+=4;//Indent;Token*token=TokenScanfrom_file;if token-type==IF{couttoken-nameendlendl;ProcedureCfrom_file;token=TokenScanfrom_file;Indent;if token-type==THEN{couttoken-nameendlendl;Proceduresfrom_file;}else{exit-1;}else if token-type==WHILE{ProcedureCfrom_file;token=TokenScanfrom_file;Indent;if token-type==DO{couttoken-nameendlendl;Proceduresfrom_file;}else{exit-1;n n}else if token-type==IDN{cout id:token-nameendlendl;token=TokenScanfrom_file;if token-type==EQU{Indent;couttoken-nameendlendl;ProcedureEfrom_file;}else{exit-1;子程序结束indentation-=4;//return0;㊀int Proc dureCifstream from_file{Indent;子程序开始incantation+=4;//Token*token;ProcedureEfrom_file;;㊀㊀token=Tok nScanfrom_fil Indent;if token-type==MORE{couttoken-nameendlendl;ProcedureEfrom_file;㊀㊀}else iftok n-typ==LESS{couttoken-nameendlendl;ProcedureEfrom_file;}else{exit-1;子程序结束indentation-=4;//return0;}工㊀int ProcedureEifstreamfrom_file{nd nt;n ncoutE endlendl;子程序开始indentation+=4;//Token*token;ProcedureTfrom_file;while true{token=TokenScanfrom_file;if token-type==ADD{Indent;couttoken-nameendlendl;;㊀㊀㊀ProcdurT}else if token-type==MINUS{Indent;couttoken-nameendlendl;ProcedureTfrom_file;}else{㊀・for int i=0;iinttoken-name.length;f rom_f ilung i++;//回退㊀t}子程序结束indentation-=4;//return0;子程序结束indentation-=4;//return0;}int ProcedureTifstreamfrom_file{Indent;子程序开始indentation+=4;//Token*token;ProcedureFfrom_file;while true{token=TokenScanfrom_file;if token-type==MUL{Indent;couttoken-nameendlendl;ProcedureFfrom_file;}else if token-type==DIC{工㊀nd nt;couttoken-nameendlendl;ProcedureFfrom_file;}else{〉;㊀㊀・for inti=0;iinttok n-nam length;i++f rom_f ile.unget//回退子程序结束incantation-=4;//return0;}子程序结束indentation-=4;//return0;{㊀}int ProcedureFifstream工㊀nd nt;n ncoutF endlendl;子程序开始indentation+=4;//Token*token;㊀tok n=TokenScanfrom_file;if token-type==LBRAC{couttoken-nameendlendl;ProcedureEfrom_file;;㊀㊀token=Tok nScanfrom_fil couttoken-nameendlendl;Indent;n nif token-type==IDN{cout id:token-nameendlendl;if token-type==INT8{n Hcoutint8:ValueOfINT8token-valueendlendl;n nif token-type==INT10{cout intlO:token-valueendlendl;}if token-type==INTI6{n ncoutintl6:ValueOfINTI6token-valueendlencil;子程序结束indentation-=4;//return0;实验结果、消除左递归,提取左因子之后的、对应的子程序的编写问题:1E T实验中遇到的问题及其解决:经过多次测试,我发现在一个超过两个运算符的时候我的、子程序expression E T就只能成功的分析出第一段的式子,后来发现*类似的产生式没有写循环E-T+T调用控制,后来在的最外层加了一个循环,然后在的首+T*whiletrue whiletrue行加入了不是+就的判定,成功解决了问题return、缩进的控制2这个实验中碰到的第二个问题就是语法树缩进的控制问题,最终通过一个全局变量indentation来控制缩进的字符数量,一个Indent函数来输出缩进其实就是空格,控制缩进数量的关键点有两个一为进入子程序的时候indentation+=4,二为结束子程序的时候indentation-=4o剩下的就是根据调试来选择在哪里输出缩进空格的问题了实验三语法制导的三地址代码生成程序语法制导定义:产生式语义规则S-id=E;S.code=E.code||genid.place E.placeC.true=newlabel;S-if Cthen SC.false=S.next;Si.next=S.next;,S.code=C.code||gen C.true:||SI.codeS-while Cdo SS.begin=newlabel;C.true=newlabel;C.false=S.next;Si.next=S.begin;,,S.code=genS.begin:||C.code||genC.true:||Si.code|I gengoto S.begin;C-EiE2C.code=Ei.code||E
2.code||,,7zgenif Ei.placeE
2.place gotoC.true||gen gotoC.falseC-EiE2C.code=Ei.code||E
2.code||,,,zgenif Ei.placeE
2.place gotoC.true||gengotoC.falseE-Ti+T2*E.place=newtemp;E.code=TI.code IIT
2.code||gen E.place TI.place+T
2.place;TI.place=E.place;TI.code=E.code;+E-Ti-T2*E.place=newtemp;E.code=TI.code IIT
2.code||gen E.place TI.place-T
2.place;TI.place=E.place;TI.code=E.code;+E-TE.place=T.place;E.code=T.codeT-FT.place=F.place;T.code=F.codeT.place=newtemp;T-Fl*F2*T.code=Fl.code||F
2.code||gen T.placeFl.place F
2.place;Fl.place=T.place;Fl.code=T.code;+T.place=newtemp;T-Fl/F2*T.code=Fl.code||F
2.code||gen T.place Fl.place/F
2.place;Fl.place=T.place;Fl.code=T.code;+F-EF.place=E.place;F.code=E.codeF-idF.place=id.name;F.code=F-int8F.place=int
8.value;F.code=F-intlOF.place=intlO.value;F.code=F-intl6F.place=intl
6.value;F.code=三地址代码生成器的数据结构的属性定义文/type defstruct{/*Schar code[CODESIZE];int begin;int next;}AttrS;type defstruct{/*E的属性定义大/char code[CODESIZE];//CodeSize=500char place[BUFSIZE];//BufSize=200}AttrE;的属性定义大/type defstruct{/*C工㊀char cod[CODES ZE];;//用来标记入口用来标己入口㊀int c_fals intc_true;//i}AttrC;的属性定义文/type defstruct{/*T工=㊀㊀㊀char cod[CODES ZE];//Cod Siz500工=㊀㊀char plac[BUFS ZE]://BufSiz200}AttrT;的属生定义大/type defstruct{/*F tcharcode[CODESIZE];//CodeSize=500char place[BUFSIZE];//BufSize=200}AttrF;的属性定义大/type defstruct{/*IDNchar idname[BUFSIZE];int entry;}AttrIDN;三地址生成器算法:,㊀㊀㊀int ProcdureSifstr amAttrS s{的属性AttrC c;//C的属性AttrS si;//si的属性AttrE e;//e;//用来暂存当下一个是工时,的的㊀㊀char tmp_idn_nam
[50]DN s-id:=E idnameToken*token=TokenScanfrom_file;//////////////////////////////////////////s-if Cthen SI/////////////////////////////////////////////if token-type==IF{出口有了新标签c.c_true=NewLabel;//c.c_true真则往走si.begin=c.c_true;//C SI假贝走的下一步为标签,在前si.next=c.c_false=s.next;//c U s L0面预置了一ProcedureCfrom_file c;rtoken=TokenScanfrom_file;if token-type==THEN{Proceduresfrom_file,si;;//将中n Hsprintf_ss.code,\n\t%s\nL%d:\t%s,c.code,c.c_true,si.code间代码输出至中Us,code}else{exit-1;//////////////////////////////////////////s-while Cdo SI/////////////////////////////////////////////}else if token-type==WHILE{si.next=s.begin=NewLabel;往走c.c_true=si.begin=NewLabel;//C MSI假则走的下一步为标签,在前面预置了c.c_false=s.next;//c s L0ProcedureCfrom_file,c;token=TokenScanfrom_file;if token-type==DO{Proceduresfrom_file,si;nsprintf_ss.code,\nL%d:\t%s\nL%d:\t%s\n\tgoto L%d,s.begi・n,c.code,c.c_true,si code,s.bagin;}else{exit-1;}//////////////////////////////////////////s-id:=E/////////////////////////////////////////////==工㊀㊀}else iftok n-typ DN{strcpy_stemp_idn_name,token-name.c_str;token=TokenScanfrom_file;-〉if tokentype==EQU{ProcedureEfrom_file,e;H nsprintf_ss.code,%s\n\t%s=%s,e.code,temp_idn_name e.pla ce;r}else{exit-1;}return0;int ProcedureCifstreamfrom_file,AttrC c{的属性㊀㊀AttrE1;//1的属性AttrE e2;//e2Token*token;ProcedureEfrom_file,el;token=TokenScanfrom_file;iftoken-type==MORE{ProcedureEfrom_file e2;z〉%㊀n Hsprintf_sc.code,%s%s\n\tif%s s goto L%d\n\tgoto L%d,el.code,2,code,el.place,e
2.place,c.c_true,c.c_false;}else iftoken-type==LESS{ProcedureEfrom_file,e2;㊀n nsprintf_sc.code,%s%s\n\tif%s%s gotoL%d\n\tgoto L%d,el.code,2,,,;㊀・㊀㊀code,el.place,e
2.plac cc_tru c,c_fals}else{exit-1;return0;}{㊀㊀㊀㊀int Procdur Eifstramfrom_file,AttrEAttrT tl;t2;AttrTToken*token;ProcedureTfrom_file,tl;while true{㊀tok n=TokenScanfrom_file;iftoken-type==ADD{ProcedureTfrom_file,t2;strcpy_se.place,NewTemp;n nsprintf_s e.code,%s%s\n\t%s=%s4-%s,tl.code,t
2.code,e.pl,㊀ace,tl.plac t
2.place;//这里是关键,用和临时记录了上一次的和㊀tl.code tl.plac whilee.code e.place,随着的不断加深,的代码会不断长长㊀whil tlstrcpy_stl.code,e.code;strcpy_stl.place,e.place;}else iftoken-type==MINUS{t2;ProcedureTfrom_file,strcpy_se.place,NewTemp;㊀・㊀,・㊀,㊀・sprintf_s cod%s%s\n\t%s=%s-%s”,tl code,t
2.cod place,tl.place,t
2.place;strcpy_stl.code,e.code;strcpy_stl.place,e.place;}else{for inti=0;iinttoken-name.length;i++{;//回退f rom_f ile.unget}//////////////////////////////////////////E-T/////////////////////////////////////////////strcpy_se.place,tl.place;H nsprintf_se.code,%s,tl.code;break;return0;}int ProcedureTifstreamfrom_file,AttrT t{AttrF fl;AttrF f2;Token*token;fl;ProcedureFfrom_file fwhiletrue{㊀tok n=TokenScanfrom_file;iftoken-type==MUL{目录实验一词法分析程序的设计与实现3词法的正规式描述:3状态图4词法分析程序数据结构与算法4词法分析算法5实验结果7实验中遇到的问题及其解决
8、保留字的检测问题
18、关于为首位的数字是、和的判断问题2int8intlO intl
68、关于回退的问题38实验二自顶向下的语法分析一递归子程序法9改写后的产生式集合9化简后的语法图9递归子程序算法10实验结果13实验中遇到的问题及其解决
14、消除左递归,提取左因子之后的、对应的子程序的编写问题1E T
14、缩进的控制214实验三语法制导的三地址代码生成程序15语法制导定义15三地址代码生成器的数据结构16三地址生成器算法17实验结果21实验中遇到的问题及其解决
22、根据化简后的产生式修改语法制导定义
122、使用真假出口法和继承属性来确定的标号2goto22ProcedureFfrom_file,f2;strcpy_st.place,NewTemp;・n nsprintf_st code,%s%s\n\t%s=%s*%s,fl.code,f
2.code,t.place,fl.place,f
2.place;strcpy_sfl.code,t.code;strcpy_sfl.place,t.place;==㊀㊀}else iftok n-typ DIC{ProcedureFfrom_file,f2;strcpy_st.place,NewTemp;nsprintf_st.code,%s%s\n\t%s=%s/%s,f
1.code,f
2.code,t.pla ce,fl.plac,㊀f
2.place;,;㊀・㊀strcpy_sfl.cod tcodstrcpy_sfl.place,t.place;}else{for inti=0;iinttoken-name.length;i++{;//回退f rom_f ile.unget strcpy_st.place,fl.place;nsprintf_st.code,%s,fl.code;break;}return0;int ProcedureFifstreamfrom_file,AttrF f{AttrE e;Token*token;char temp_value
[50];;㊀㊀token=Tok nScanfrom_filif token-type==LBRAC{ProcedureEfrom_file,e;strcpy_sf.place,e.place;//f.place=e.placensprintf_sf.code,%s,e.code;;//匹酉己右括号token=TokenScan from_f ile}iftoken-type==IDN{strcpy_sf.place,token-name.c_str;Hsprintf_sf.code,\0;iftoken-type==INT8{sprintf_stemp_value,—d”,ValueOfINT8token-value;strcpy_sf.place,temp_value;Hsprintf_sf.code,\0;iftoken-type==INT10{%,//sprintf_stemp_value,d”_itoa_stoken-value,;strcpy_sf.place,token-value.c_str;・n nsprintf_sf code,\0;iftoken-type==INTI6{工㊀nsprintf_stemp_value%d ValuOf NT16token-value;strcpy_sf.place,z rtemp_value;n nsprintf_sf.code,\0;return0;实验结果口input-记事本文件F编辑E格式查看V帮助Htvhi1ea3+l50xa doif x207then whileyz doy=x*y/z这是三地址程序的输入,存在名为由文本文档中it.txt•实验中遇到的问题及其解决:、根据化简后的产生式修改语法制导定义:1主要难点在于什此种产生式当循环调用的次数多于的时候需要做一步ET1T2*1将上一次循环的和暂存到和中,这Tl.place=E.place;Tl.code=E.code E.code E.place jTl.code Tl.place样在下一次循环中通过二就可以正确的E.code=Tl.code||T
2.code||genE.place Tl.place+T
2.place重新生成的新的三地址代码E、使用真假出口法和继承属性来确定的标号2goto在本程序中并没有使用拉链回填的方法实现而是使用下面的实现方法例如,goto,S fifethen S和这种的产生式,Swhile Cdo S在中,先创建所有用到的非终结符的属性结构体1S的属性AttrC c;//C的属性AttrS si;//si的属性AttrE e;//e在完和后,用以下语句构造真假出口2match if whileif token-type==IF{口有了新标签c.c_true=NewLabel;//c.c_truetB真则往走si.begin=c.c_true;//C SI假贝走的下一步为标签,在si.next=c.c_false=s.next;//c ljsL0前面预置了一…}else iftoken-type==WHILE{si.next=s.begin=NewLabel;则往走c.c_true=si.begin=NewLabel;//CM SI假则走的下一步为标签,在前面预置了c.c_false=s.next;//c sL
0...}一⑶在构造完真假出口后进入的子程序将中定义的的属性传进去,也就实现了将标号传进C SC去ProcedureCfrom_file,c;这样子在子程序结亦需要的时候定位到正确的标号4c gotopsprintf_sc.code,%s%s\n\tif%s%sgotoL%d\n\tgoto L%d e
1.rcode,e
2.code,el.place,e
2.place,c.c_true,c.c_false;实验一词法分析程序的设计与实现词法的正规式描述标识符〈字母〉〈字母》I〈数字字符》*十进制整数0|1|2|3|4|5|6|7|8|90|1|2|3|4|5|6|7|8|9*八进制整数00|1|2|3|4|5|6|70|1|2|3|4|5|6|7*十六进制整数0x|X0|l|2|3|4|5|6|7|8|9|a|b|c|d|e|f0|l|2|3|4|5|6|7|8|9|a|b|c|d|e If*运算符和分隔符+-*/>〈=;关键字if thenelse whiledo.状态图:词法分析程序数据结构与算法//单词类class Token{public:种别int type;//属性值string value;//单词具体内容string name;//Token{type=DEFAULT;value=NONE_OF_VALUE;-Token{}Tokenint type,string value,string name:typetypervaluevalue,name name{}};词法分析算法:Token*TokenScanifstream from_file{用于保存从文件中读取的字符char ch;////读第一个字符inti=0;=,//用来存放的属性值㊀char value
[30]tok nch=from_file.get;while ch==BLANK||ch==TAB||ch==NEWLINE{ch=from_file.get;////////////////////////////////////以下为标识符的检测////////////////////////////////////////////////////////////////////////////if isalphach{value[i++]=ch;ch=from_file.get;////判断后续的是否为工的成分数字或字母DNwhile isalnumch{value[i++]=ch;ch=from_file.get;//直到不是工成分,回退一字符DNfrom_file.unget;这里加上保留字检测部分//TODO//进行字符串的对比,即可比较出保留字,通过压栈的形式来获得完整的属性值////////////////////////////////////以下为保留字的检测////////////////////////////////////////////////////////////////////////////if strcmpvalue,WORD_IF==0return newTokenIF,NONE_OF_VALUE,WORD_IF;if strcmpvalue,WORD_THEN==0return newTokenTHEN,NONE_OF_VALUE,WORD_THEN;if strcmpvalue,WORD_ELSE==0return newTokenELSE,NONE_OF_VALUE,WORD_ELSE;if strcmpvalue,WORD_WHILE==0return newTokenWHILE,NONE_OF_VALUE,WORD_WHILE;if strcmpvalue,WORD_DO==0return newTokenDO,NONE_OF_VALUE,WORD_DO;return newTokenIDN Zvalue,value;n mmm mmm mnn mnm/以下为数字的检测////////////////////////////////////////////////////////////////////////////if isdigitch{value[i++]=ch;//如果第一个数字是则有可能是工的、或工0,NT1001NT8NT16{if ch==ch=from_file.get;if ch=ch181||ch==1x|||ch==1X1{//如果后面紧跟着数字则为工0-8,NT8if isdigitch{101while ch=ch*8{value[i++]=ch;ch=from_file.get;from_file.unget;return newTokenINT8,value,value;value[i++]=ch;//到这一步的都是INT16ch=from_file.get;1f1{while isdigitch||ch=1a1ch=value[i++]=ch;这里没有解决的问题//TODO:Oxrtr ch=from_file.get;from_file.unget;return newTokenINT16,value,value;后面的不为的或或等或进制特征字符,则为进制的回退一个字}else{//00-7digit x X816100,符from_file.unget;return newTokenINT10,value,value;//能到这一步的都是工且不为打头NT10,0ch=from_file.get;while isdigitch{value[i++]=ch;ch=from_file.get;from_file.unget;return newTokenINT10,value,value;////////////////////////////////////以下为运算符的检测////////////////////////////////////////////////////////////////////////////+”);case return new TokenADD,value,ncase return new TokenMINUS,value,….case»*».return newTokenMUL,value,n夫”);case return new TokenDIC,value,n/“);case return new TokenMORE,value,”“);case yreturn newTokenLESS,value,nn;case1_I.return newTokenEQU,value,”=);case『(,returnnewTokenLBRAC,value,nn;case returnnew TokenRBRAC,value,nn;!.f.case,•returnnewTokenCOMMA,value,n;n;value[i++]=ch;switch ch{default:ErrorHandlefrom_file;break;returnnewTokenDEFAULT,NONE_OF_VALUE,NONE_OF_VALUE;实验结果:C:\windows\system32\cmd.exeelse idel2!23\00\07I000!0!82[0x00I0xff!12!100呈序结束请按任意键继续.嗖狗拼音输入法全、保留字的检测问题:1实验中遇到的问题及其解决:一开始的时候我的想法是遇到、、、等单词的首字母时即开始划分状态,后ifwhiledo then来发现这样子判断的分支会特别多,而且效率不是很高,对保留字集合的扩展支持的也不是很好后来我发现保留字存在于标识符的子集,所以为什么不先判断标识符然后再判断是不是保留字呢?后来我就照着这个思路成功实现了功能、关于为首位的数字是、和的判断问题2int8intlO intl6当读入的第一个字符为时,可能为、可能是的也可能是的开头,当下0int8intio0intl6一个字符是时,开始进行的匹配;当下一个字符是或时,开始进行的匹0~7int8xXintl6配;当下一个字符为其他字符时,说明这是一个十进制的此时还需进行一字节的回退
0、关于回退的问题3有些时候需要进行回退,否则不能正常的进行完整个分析过程,需要进行回退的场合为:⑴匹配标识符或保留字时,向后逐字读取的时候当下一个不是字母或数字的时候需要将读取的字符回退,才能继续向下进行;判断为的的时候需要一步回退2intlO后面的不为的或或等或进制特征字符,则为进制的else{//00-7digit xX816100,回退一个字符from_file.unget;returnnewTokenINT10,value,value;⑶判断数字的时候到最后一个不为数字的都需要回退实验二自顶向下的语法分析一递归子程序法改写后的产生式集合:S-id=E;S-if Cthen S;S-while Cdo S;C-EE;C-E=E;E-T+T*;E-T-T*;T-F*F*;T-F/F*;;F-EF-id;F-int8;F-intlO;F-intl6;化简后的语法图:。