




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、+ - + - ident if 条件then 语句语句else ident 语句:= += -= 表达式for 语句to downto 表达式to 语句因子number ident + - ident 表达式表达式表达式()()()- + 1. 增加一维数组类型(可增加指令)增加一维数组后的声明语句语法描述图:ebnf 语法描述::=var , 识别数组部分代码实现,在getsym 和 enter 里改动if(ch=)/ 如果是 则认为是数组 getchdo; getsymdo; sum=num;/把 getsym 取出的数字赋给sum,作为数组的维数if(ch=)/ 维数后的应该是 get
2、chdo; sym=arrayp; else error(33);/ 如果没有 报错 if(sum1) error(34);/ 数组维数不能为0 /- 把一维数组当作变量,把数组填入名字表table 里,在 enter- switch(k) case array: /数组时table(*ptx)-1.size=sum;/ 为数组变量开辟一个长度sum 的空间for(i=0;isum) i=i+sum+1;/ 使用单元为数组首单元+该单元编号 +1 else error(35); sum=0; return i; 详细版添加一维数组需要对pl0进行如下修改 : (未更改 getsym?! )添加
3、一维数组变量类型的声明的处理以及识别; 处理一维数组作为变量时在表达式及语句中的变量引用情况;处理一维数组进行 +和运算;处理一维数组在运行栈里的存取问题;检测一维数组下标界合法性问题。完成数组的添加的主导思想为,把数组元素转化为变量处理,从而充分利用之前为变量设定的各种操作。(1) 添加一维数组变量类型的声明的处理以及识别首先在枚举类型 kind 中添加 array及 null。修改后 kind 为: enum object constant, variable, procedur, array, null, ; 同时结构体类型中tablestruct中的 size 除了表示 procedu
4、re 的大小外 ,同时用于表示数组的大小。添加数组左右中括号的symbol,左中括号lepa, 右中括号ripa, 同时修改symnum 变为 43(41+2), 以及 init()函数中进行如下修改ssym+=plus; ssym-=minus; ssym*=times; ssym/=slash; ssym(=lparen; ssym)=rparen; ssym=eql; ssym,=comma; ssym.=period; /ssym#=neq; ssym;=semicolon; ssym=lepa;/数组用新增ssym=repa;/数组用新增添加 int 类型全局变量 arraysize
5、 。用于暂时存储数组大小。在变量声明处理过程vardeclaration中添加对一维数组的声明处理。若变量后接左中括号则为数组。修改如下: int vardeclaration(int * ptx,int lev,int * pdx) int i; char idtempal+1;/临时保存数组名字if(sym=ident) strcpy(idtemp,id); getsymdo; /如果是数组if(sym=lepa)/数组的左中括号 getsymdo; if(sym=number)/a中的中括号里是数字的话 *pdx=*pdx+num;/ 为数组分配空间arraysize=num;/保存数组
6、的长度 else if(sym=ident)/a 中的中括号里是变量的话 /要检查是不是以声明的常量i=position(id,*ptx);/ 查找名字表if(i=0) error(11);/标识符未说明 else if(tablei.kind=constant)/ 标识符的属性是常量 *pdx=*pdx+tablei.val;/ 为数组分配空间arraysize=tablei.val;/保存数组的长度 else error(25);/数组下标定义不符合规定,应为常量 /if else error(25);/数组下标定义不符合规定,应为常量 /else strcpy(id,idtemp);/恢
7、复数组名字 id enter(array,ptx,lev,pdx);/ 填写名字表getsymdo; if(sym!=ripa)/ 如果不是 结尾 error(26); else getsymdo; /if /下个字符是逗号或者分号,则不是数组,是变量else if(sym=comma|sym=semicolon) enter(variable,ptx,lev,pdx);/填写名字表/getsymdo; else error(4); return 0; 同时修改 enter 函数 , 增加对数组的支持void enter (enum object k,int *ptx,int lev, int
8、 *pdx) (*ptx)+; strcpy(table(*ptx).name,id); /* 全局变量 id 中已存有当前名字的名字*/ table(*ptx).kind=k; switch(k) case constant: /*常量名字 */ if (numamax) error(31); num=0; table(*ptx).val=num; break; case variable: /*变量名字 */ table(*ptx).level=lev; table(*ptx).adr=(*pdx); table(*ptx).size=0; (*pdx)+; break; /* 过程名字
9、*/ case procedur: table(*ptx).level=lev; break; case array: /* 数组名字 */ table(*ptx).level=lev; table(*ptx).adr=(*pdx)-arraysize; table(*ptx).size=arraysize; break; (2)处理一维数组作为变量时在表达式及语句中的变量引用情况,以及完成对数组越界的处理在修改 statement与 factor 函数前 ,需对虚拟机的中间代码添加对数组相关操作的支持。修改 fct 枚举类型如下enum fct lit, opr, lod, sto, cal
10、, inte, jmp, jpc, tra,jud,wta,rda, ; 在 interup 解释函数中添加对上述新增功能的解释.代码如下 : case tra:/ 将数组的下标范围入栈st=i.a; t+; break; case rda:/ 读数组数据tmd=base(i.l,s,b); st=stmd+i.a+st-1; t+; break; case wta:/ 写数组数据tmd=base(i.l,s,b); stmd+i.a+st-2=st-1; t-; break; case jud:/判断数组下标的合法性t-; if(st-1=st) error(41);/定义数组下标溢出错误p
11、rintf( 数组下标溢出错误 ); break; 接下来可以修改 stament语句,如下: int statement(bool* fsys,int * ptx,int lev) int i,cx1,cx2; bool nxtlevsymnum; enum symbol addop;/ 用于存储运算类型 ,新增object type=null; if(sym=ident) i=position(id,*ptx); if(i=0) error(11); else /数组元素或变量if(tablei.kind!=variable &tablei.kind!=array) error(1
12、2); i=0; else getsymdo; if(sym=lepa)/如果是数组 getsymdo; /处理里的表达式memcpy(nxtlev,fsys,sizeof(bool)* symnum); nxtlevripa=true;/ 表达式后接符号为右中括号expressiondo(nxtlev,ptx,lev); gendo(tra,0,tablei.size);/生成将数组下标范围入栈指令gendo(jud,0,0);/作用判断下标合法性 ,完成了数组越界的处理if(sym!=ripa) error(26);/接下来的单词不为右中括号 getsymdo; /if(sym=lepa)
13、 if(sym=becomes) /省略未改动部分 else /省略 +=,-=等语句判别的代码,同时在各代码中取消存储到变量的语句用下面的if 语句统一代替if(type=array) gendo(wta,lev-tablei.level,tablei.adr); /* 把数组元素的值压入栈*/ else gendo(sto,lev-tablei.level,tablei.adr); /* 把变量的值压入栈*/ 在因子处理程序中,添加对一维数组的支持,在判断第一个单词为ident 后的switch 语句中 ,添加如下代码case array: getsymdo; if(sym=lepa) m
14、emcpy(nxtlev,fsys,sizeof(bool)* symnum); nxtlevripa=true; getsymdo; expressiondo(nxtlev,ptx,lev); gendo(tra,0,tablei.size);/生成将数组下标范围入栈指令gendo(jud,0,0);/判断下标合法性gendo(rda,lev-tablei.level,tablei.adr); /* 把数组元素的值压入栈 */ if(sym!=ripa)error(42);/ 定义中括号不匹配错误elsegetsymdo; break; 同时把所有读取变量存取变量的代码替换为如下代码读变量的
15、替换代码if(type=array) gendo(rda,lev-tablei.level,tablei.adr);/*把数组元素的值压入栈*/ else gendo(lod,lev-tablei.level,tablei.adr);/*把变量的值压入栈*/ 写变量的替换代码if(type=array) gendo(wta,lev-tablei.level,tablei.adr); /* 把数组元素的值压入栈 */ else gendo(sto,lev-tablei.level,tablei.adr); /*把变量的值压入栈 */ 上述代码中 type 为 object 类型变量。在判断变量是
16、否为array 时对其赋值。扩充一维数组类型功能扩充一维数组类型功能需要:一维数组变量类型的声明;一维数组的识别分析;一维数组作为变量时在表达式中的变量引用情况;一维数组可以进行+和运算;一维数组在运行栈里的存取问题;一维数组下标界合法性问题。一维数组的文法如下::= | := 扩充的语法描述见结构设计中的pl/0 分程序和主要语句的语法描述中的描述图。 在标识符的属性类型里增加了array 数组类型, 详细见报告上面的说明。在虚拟机代码指令操作码中增加了六条指令:gar,/根据栈顶的偏移地址从数组中取值到新的栈顶 sar,/根据次栈顶的偏移地址把栈顶的值存入数组 shd,/将栈顶的值下移到次
17、栈顶,栈顶出栈,即次栈顶成为栈顶 del,/出栈顶jud,/判断数组下标合法性tra,/将数组的下标范围入栈,gendo(tra,0,数组下标最大值 );其中增加的指令中gar,sar,shd,del 是用于数组变量引用时的处理,jud,tra 是用于数组下标合法性的判断处理。详细运用见下面分析。下面一一分析扩充一维数组的情况:一维数组变量类型的声明:编译器一开始运作的时候,先对声明部分进行分析后填名字表 t able 。数组类型属于变量,所以,在分析声明部分的时候,遇到变量 var 声明时,读完变量标识符后再读下一个字符,如果下个字符sym=lepa 即 时,就将变量认定为数组变量,后采用数
18、组变量的分析处理。在变量分析函数:int vardeclaration(int * ptx,int lev,int * pdx);中对数组变量声明的处理如下流程:一维数组的识别分析:一维数组的识别分析过程是数组变量引用处理之前的基础,识别过程大体如下:1)读到sym=ident ,读下个单词;2) 如果该单词是 l epa, 即 , 判断为数组变量, 后读下个单词,采用表达式 expression函数处理 里的式子,后读下个单词,遇到r ipa ,即 ,识别数组变量完毕;3)如果该单词不是 l epa,即判断为正常变量,采用正常变量的情况处理。一维数组在表达式中的变量引用情况:一维数组的变量引
19、用情况,先识别是一维数组变量, 后处理生成中间代码。下面分析一维数组中间代码的生成问题。1)一维数组变量作为语句的开始符号,即赋值语句 ai:=或者 ai+;这种形 式的语句对于赋值语句ae1:=e2 的情况,中间代码结构如下图:2) 一维数组变量作为表达式里面的某个因子参加表达式的运算情况在因子处理函数i nt factor(bool*fsys,int *ptx,int lev);中,如果遇到数组变量时,后读 下个单词,如果是+,- 的情况,分析情况见下面;如果不是+,-的情况,按下面分析处理。即对于表达式 :e1 ae2 e3 中, 中间代码生成情况如下图:以例子 b:=2*a1-4;解析
20、一下因子 a1 中间代码的生成情况。3)对于一维数组变量与运算符+,- 的情况见下面。一维数组的 +和运算分析:对一维数组的 +和运算分析和普通变量的+、- 运算分析的流程是基本相同的,只是在识别一维数组变量和生成中间代码有些差别。生成中间代码的差别在于:分两种情况讨论。作为表达式里面的因子ae+ 或者 ae 生成的中间代码结构如下:下面给出表达式中因子ae+ 的中间代码作为表达式里面的因子+ae 或者 ae生成的中间代码结构如下:下面给出表达式中因子+ae 的中间代码:一维数组在运行栈里的存取问题,包括指令增加和优化:对于优化运行栈的存取问题,是因在调试的时候,在调试程序:var a2;be
21、gin a1:=1;while a11000dobegin+a1;end;write(a1);end.输出的结果是 1,后经过细细检查发现是运行栈溢出的问题。运行栈的大小为:#define stacksize 500,在一般的简单程序是足够的,但是为什么会溢 出呢?原来在运行的过程中,忘记删除多余的数据, 从而导致运行栈在每次循环总会将 栈顶指针上移,从而运行栈溢出了。后根据这个问题增加了指令shd 和del ,对多余的数据进行删除,达到中间代码的优化。一维数组下标界合法性问题:对于处理一维数组下标界的合法性问题,增加了指令 t ra 和j ud,指令 t ra 是将数组变量 的下标最大值取到
22、栈顶,后指令 j ud 是根据栈顶的下标界限值与次栈顶的实际下标值相 比较检查下标是否合法。6. 扩充取余运算符% 取余运算符 % 采用了指令 opr 0 7,只需在初始化函数里增加 ssym%=mod;/取余的语句,后在解释函数里增加指令 opr 0 7 的功能就行了。2. 增加for语句支持增加 pascal 的 for语句 : for := to do for := downto do 其中,语句的循环变量的步长为1,语句的循环变量的步长为-1 for 语句的语句语法图如下:for i:= e1 to e2 do s1 循环语句 algol 等价于:i:= e1; goto over;
23、again :i:= i+1 over : if ie2 then begin s1; goto again end; (注意程序中基础用到循环控制变量i,因此entry(i)必须被保存下来,而pascal 这样的语言中,循环变量在循环外也是可见的,本次扩充约定循环步长为1 或者 -1。具体需要在程序 staement()添加for 的句法判断 ) 首先 ,词法分析部分增加关键字在 symbol 里增加 forsym, tosym, downtosym,对应 symmax=44 ; norw = 25; 初始化中strcpy(kword10,for); wsym 10=ifsym; strcp
24、y(kword22,to); wsym22=tosym; strcpy(kword 7,downto); wsym 7=downtosym; 其次 ,修改 statement ,代码如下:elseif (sym=forsym) / 检测到 for 语句 getsymdo; if (sym=ident) i=position(id,*ptx); if (i=0) error(11); else if (tablei.kind!=variable) / 赋值语句中,赋值号左部标识符属性应是变量 error(12);i=0; else getsymdo; if (sym!=becomes) erro
25、r(13); / 赋值语句左部标识符后应是赋值号:= else getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlevtosym=true; /后跟符to和downto nxtlevdowntosym=true; expressiondo(nxtlev,ptx,lev); / 处理赋值语句右部的表达式e1 gendo(sto,lev-tablei.level,tablei.adr); / 保存初值switch (sym) case tosym: / 步长为的向上增加getsymdo; cx1=cx; / 保存循环开始点 /将循环判断变
26、量取出放到栈顶gendo(lod,lev-tablei.level,tablei.adr); memcpy(nxtlev,fsys,sizeof ( bool )*symnum); / 处理表达式 e2 nxtlevdosym=true ; / 后跟符 do expressiondo(nxtlev,ptx,lev); /* 判断循环变量条件,比如for i:=e1 to e2 do s中,判断 i 是否小于e2,如小于等于, 继续循环, 大于的话,跳出循环*/ gendo(opr,0,13); / 生成比较指令,i 是否小于等于 e2的值cx2=cx; / 保存循环结束点/ 生成条件跳转指令,
27、跳出循环,跳出的地址未知gendo(jpc,0,0); if (sym=dosym) / 处理循环体 s getsymdo; statement(fsys,ptx,lev); / 循环体处理/ 增加循环变量步长为 /将循环变量取出放在栈顶gendo(lod,lev-tablei.level,tablei.adr); gendo(lit,0,1); / 将步长取到栈顶gendo(opr,0,2); / 循环变量加步长/ 将栈顶的值存入循环变量gendo(sto,lev-tablei.level,tablei.adr);gendo(jmp,0,cx1); / 无条件跳转到循环开始点/* 回填循环结
28、束点的地址,cx为else 后语句执行完的位置,它正是前面未定的跳转地址*/ codecx2.a=cx; else error(29); /for语句中少了 do break; case downtosym: / 步长为的向下减少getsymdo; cx1=cx; / 保存循环开始点/ 将循环判断变量取出放到栈顶gendo(lod,lev-tablei.level,tablei.adr); memcpy(nxtlev,fsys,sizeof ( bool )*symnum); / 处理表达式 e2 nxtlevdosym=true ; / 后跟符 do expressiondo(nxtlev,
29、ptx,lev); /* 判断循环变量条件,比如for i:=e1 downto e2 do s 中,判断 i 是否大于等于 e2,如大于等于,继续循环,小于的话,跳出循环*/ gendo(opr,0,11); / 生成比较指令, i 是否大于等于 e2的值cx2=cx; / 保存循环结束点/ 生成条件跳转指令,跳出循环,跳出的地址未知gendo(jpc,0,0); if (sym=dosym) / 处理循环体 s getsymdo; statement(fsys,ptx,lev); / 循环体处理 / 增加循环变量步长为/ 将循环变量取出放在栈顶gendo(lod,lev-tablei.le
30、vel,tablei.adr); gendo(lit,0,1); / 将步长取到栈顶gendo(opr,0,3); / 循环变量加步长/ 将栈顶的值存入循环变量gendo(sto,lev-tablei.level,tablei.adr); gendo(jmp,0,cx1); / 无条件跳转到循环开始点/* 回填循环结束点的地址,cx为else 后语句执行完的位置,它正是前面未定的跳转地址*/ codecx2.a=cx; else error(29);/for语句中少了 do break; else error(19); /for语句后跟赋值语句,赋值语句左部是变量,缺少变量 其跳转图为) 在
31、statement 中添加,类似 else 的方式,主要是处理好如何出入栈的问题,代码中有详细的注释。if(sym=forsym) enum symbol temp;/ 定义临时变量,来判断是to 还是 downto 的区别getsym(); if(sym=ident) i=position(id,*ptx); /查找变量标识符if(i=0) error(11); / 标识符没有找到else if(tablei.kind=constant|tablei.kind=procedur) error(12); / 变量不能为常数或过程i=0; getsym(); if(sym=becomes) /变
32、量赋初始值 getsym(); /处理第一个运算表达式,放入栈顶expressiondo(fsys,ptx,lev); if(sym=tosym) / 如果为 to cx1=cx; /cx1 记录当前代码段作为开始循环位置gen(sto,lev-tablei.level,tablei.adr); /变量赋值gen(lod,lev-tablei.level,tablei.adr); /变量的值放入栈顶getsym(); /计算第二个运算表达式,放入栈顶expressiondo(fsys,ptx,lev); gen(opr,0,13); /判断运算是否大于cx2=cx; /cx2 记录当前代码段,
33、用于jpc 的跳转地址的回填gen(jpc,0,0); temp=tosym; else /downto 与 to 几乎一样,区别在于判断运算是否小于if(sym=downtosym) cx1=cx; gen(sto,lev-tablei.level,tablei.adr); /变量赋值gen(lod,lev-tablei.level,tablei.adr); /变量的值放入栈顶getsym(); expressiondo(fsys,ptx,lev); gen(opr,0,11);/判断运算是否小于cx2=cx; gen(jpc,0,0); temp=downtosym; else error
34、(19); if(sym=dosym) getsym(); /做 do 后面的 else error(18); /缺少 do statementdo(fsys,ptx,lev); gen(lod,lev-tablei.level,tablei.adr);/读取变量的值 ,放入栈顶gen(lit,0,1); / 设置步长为1 switch(temp) case downtosym: gen(opr,0,3); break; /downtosym:栈顶值减1 case tosym: gen(opr,0,2); break; /tosym :栈顶值加1 gen(jmp,0,cx1); / 无条件跳转
35、到cx1 记录的地址段codecx2.a=cx; / 回填 jpc的跳转地址cx / if(sym=ident) else error(97); /for 后面是非法标识符,错误代码自己定义 /forsym/for语句处理完增加 c 语言的 for 语句:(考虑不够完善,但思路基本可以的一个版本)for(变量:= ;变量常数; 变量变化) s1 三元式可以写为 1:变量:= (赋值语句,调用 statementdo(fsys,ptx,lev)即可)2: 变 量 常 数 ( 这 里 可 以 是 或 = , 假 设 先 考 虑 递 增 , 则 调 用conditiondo(nxtlev,ptx,l
36、ev)) (这里位置是后面s1执行完需要返回的地址,所以需要记录 cx1=cx) 3: condition执行结 果 可能 为 真或假, 所以 这里需 要 生成 一个 条件 跳转指 令gendo(jpc,0,0);(但位置需要后面才能决定,也就是为假时,需要跳转到s1的后面! ,所以记录 cx2=cx) 4: 如果上面结果为真,则应该执行s1部分,但是代码是顺序扫描的,接下来它要生成的四元式为变量变化部分!,所以这里必须生成一个无条件跳转指令gendo(jmp,0,0);(但位置需要等变量变化部分翻译完后,也就是开始s1的部分时才回填,所以记录cx3=cx) 5:如果接下来为 ; 则继续翻译变
37、量变化部分statementdo(nxtlev,ptx,lev); (但这里在s1执行完后要跳转回来,所以需要记录,cx4=cx) 6:接下 来 翻 译 s1, 再翻 译 s1 之前 , 我们 发 现cx3 所 在 的 四元 式 可以 回填 了codecx3.a=cx; 7 :翻译 s1 statementdo(nxtlev,ptx,lev); /对语句进行处理 8 :生成跳转指令,回到变量变化部分:gendo(jmp,0,cx4); / 继续 for 语句第三部分的计算 9 :condition条件为假的时候的回填:codecx2.a=cxif(sym=forsym) /如果遇到for 语句
38、 getsymdo; / 获取下一token,应该是左括号if(sym!=lparen) / 如果不是左括号 error(34); printf( 格式错误,应是左括号n); else getsymdo; /获取下一token,应该是语句部分statementdo(fsys,ptx,lev); / 对语句进行处理if(sym=semicolon) / 如果是 ; getsymdo; /获取下一token,下一个应该是一个逻辑表达式 cx1=cx; / 记下当前代码分配位置conditiondo(nxtlev,ptx,lev); / 对这个逻辑表达式进行分析计算cx2=cx; /记下当前代码分配
39、位置gendo(jpc,0,0); / 生成条件跳转指令,跳转位置待定,暂时填0,e.false 的出口cx3=cx; /记下当前代码分配位置gendo(jmp,0,0); / 生成无条件跳转指令,跳转位置待定,暂时填0 if(sym=semicolon) / 如果是 ; cx4=cx; /记下当前代码分配位置getsymdo; /获取下一token statementdo(nxtlev,ptx,lev); / 对语句进行处理gendo(jmp,0,cx1); /生成条件跳转指令,跳转位置为逻辑表达式所在的位置if(sym=rparen) / 是右括号 getsymdo; /获取下一token
40、 else error(22); printf( 表达式中漏掉 )n); codecx3.a=cx; / 无条件跳转指令的跳转位置确定为for 完后的句子。statementdo(nxtlev,ptx,lev); / 对语句进行处理gendo(jmp,0,cx4); / 继续 for 语句第三部分的计算codecx2.a=cx; /生成cx2 对应的条件跳转指令的跳转位置设置为下一个四元式的位置/也就是 e.false 的出口 3. 增加-=或+=、-、+ (1) 修改 symbol enum symbol nul, ident, number, plus, minus, times, sla
41、sh, oddsym, eql, neq, lss, leq, gtr, geq, lparen, rparen, comma, semicolon, period, becomes, beginsym, endsym, ifsym, thensym, whilesym, writesym, readsym, dosym, callsym, constsym, varsym, procsym, elsesym, forsym, tosym, downtosym, returnsym, pluseql, minuseql, plusplus, minusminus, ;( 这个名字可以自己取!
42、) (2)getsym( )修改如下:if(ch=+)/ 如果字符是 +则 getchdo; if(ch=)/ +后面是 =就把 pluseq 赋给 sym sym=pluseq;getchdo; else if(ch=+)/ +后面是 +就把 inc 赋给 sym sym=inc;getchdo; else/如果后面是其他字符则认为普通加,把plus 赋给 sym sym=plus; if(ch=-) / 如果字符是 - getchdo; if(ch=) / - 后面是 =就把 minueq 赋给 sym sym=minueq;getchdo; else if(ch=- ) / - 后面是
43、- 就把 dec赋给 sym sym=dec;getchdo; else sym=minus; / +后是其他符号则认为是减,把 minus 赋给 sym statement( )修改如下:else if(sym=pluseq)/ 为加等时执行的操作 getsymdo; memcpy(nxtlev,fsys,sizeof(bool)* symnum); expressiondo(nxtlev,ptx,lev);/计算等号右边表达式的结果if(i!=0) gendo(lod,lev-tablei.level,tablei.adr);/生成指令 ,将变量放到栈顶gendo(opr,0,2);/ 生
44、成指令,栈顶加次栈顶gendo(sto,lev-tablei.level,tablei.adr);/生成指令 ,结果写变量地址 else if(sym=inc)/ 如果是自加时执行的操作 getsymdo; if(i!=0) gendo(lod,lev-tablei.level,tablei.adr);/生成指令 ,将变量放到栈顶gendo(lit,0,1);/ 生成指令,把常量1 取到运行栈顶gendo(opr,0,2);/ 生成指令,栈顶加次栈顶gendo(sto,lev-tablei.level,tablei.adr);/生成指令 ,结果写回变量 else if(sym=minueq)/
45、 如果是减等时执行的操作 getsymdo; memcpy(nxtlev,fsys,sizeof(bool)* symnum); expressiondo(nxtlev,ptx,lev);/计算等号右边表达式的结果if(i!=0) gendo(lod,lev-tablei.level,tablei.adr);/生成指令 ,将变量放栈顶gendo(opr,0,3);/ 生成指令,栈顶减次栈顶gendo(opr,0,1);/ 生成指令,结果取反,则结果为次栈顶减栈顶gendo(sto,lev-tablei.level,tablei.adr);/生成指令 ,结果写变量 else if(sym=dec
46、)/ 如果是自减时执行的操作 getsymdo; if(i!=0) gendo(lod,lev-tablei.level,tablei.adr);/生成指令 ,取变量放栈顶gendo(lit,0,-1);/ 生成指令,取常数-1 到栈顶gendo(opr,0,2);/ 生成指令,栈顶加次栈顶gendo(sto,lev-tablei.level,tablei.adr);/生成指令 ,结果写变量 该法 2: statement()增加的内容: ( 将本来 “if(sym=becomes)” 部分的内容修改为处理 +,+= ,- ,-=) ,并在 statement()中定义变量int sym2;
47、(这种方法将if(sym=becomes|sym=pluseq|sym=minuseq|sym=plusone|sym=minusone) sym2=sym; getsymdo; gendo(lod,lev-tablei.level,tablei.adr); else error(13); if(sym2=plusone|sym2=minusone)/* 准备按照 a+、a-语句处理,与read 类似 */ if(i!=0) if(sym2=plusone) gendo(lit,0,1); gendo(opr,0,2); gendo(sto,lev-tablei.level,tablei.ad
48、r); if(sym2=minusone) gendo(lit,0,1); gendo(opr,0,3); gendo(sto,lev-tablei.level,tablei.adr); else memcpy(nxtlev,fsys,sizeof(bool)* symnum); expressiondo(nxtlev,ptx,lev); if(i!=0) if(sym2=becomes) gendo(sto,lev-tablei.level,tablei.adr); if(sym2=pluseq) gendo(opr,0,2); gendo(sto,lev-tablei.level,tabl
49、ei.adr); if(sym2=minuseq) gendo(opr,0,3); gendo(sto,lev-tablei.level,tablei.adr); /else (上述 +,-,只考虑ident+或 ident的情形)详细正确版!扩充赋值运算:+= 和 -= 设计:对于+=、-=、*=和/=赋值运算符,在程序中出现的情况只有如下一种,文法的 ebnf 表示为:赋值语句 := += | -= (1)扩充的语法描述见结构设计中的pl/0 分程序和主要语句的语法描述中的描述图;(2)分析区别赋值运算符采用:读标识符后再读一个字符,后根据读到的字符转去不同的赋值语句执行。(3)中间代码生
50、成情况: +=运算符,其他赋值运算符架构是一样的,只是执行加法改为相应的算数运算。elseif (sym=pluseql) / 检测到 +符号 /i=position(id,*ptx); / 把类 x+=3的x的地址取出来gendo(lod,lev-tablei.level,tablei.adr); /* 找到变量地址并将其值入栈*/ getsymdo; if (sym=semicolon) getsymdo; memcpy(nxtlev,fsys,sizeof ( bool )* symnum); expressiondo(nxtlev,ptx,lev); gendo(opr,0,2); i
51、f (i!=0) gendo(sto,lev-tablei.level,tablei.adr); elseif (sym=minuseql) / 检测到 - 符号 / i=position(id,*ptx); / 把类 x-=3 的x的地址取出来gendo(lod,lev-tablei.level,tablei.adr); /* 找到变量地址并将其值入栈*/ getsymdo; 读到 +=运算符单词求+=运算符后的表达式expressiondo(nxtlev,ptx,lev); 取+=左部的标识符的值到栈顶gendo(lod,lev-tablei.level,tablei.adr); 执行加法
52、gendo(opr,lev-tablei.level,2); 保存赋值后的结果gendo(sto,lev-tablei.level,tablei.adr); if (sym=semicolon) getsymdo; memcpy(nxtlev,fsys,sizeof ( bool )* symnum); expressiondo(nxtlev,ptx,lev); gendo(opr,0,3); if (i!=0) gendo(sto,lev-tablei.level,tablei.adr); 增加运算: + 和 - :对于+和-运算符,扩充时要注意存在+,-有两个情况: 1、作为语句的时候;2
53、、作为表达式中的因子的时候. (1) 作为语句的时候,有四种情况: a+ +a a- -a 文法的 ebnf 表示形式为::= + | - | + | - (2) 作为因子的时候,有两种情况a+和 a-作为因子,比如: b:=a+*a-;语句+a 和-a 作为因子,比如: b:= -a+2*+a;语句文法的 ebnf 表示形式为::=. + | - | + | - . 其中的 .表示前后都可以有其他的项或因子(1)作为语句+ - 符号分为以下两种情况考虑: 情况 1 对于自增自减符号置后的只需要在判断+= -=后面添加句法分析即可:/*后置自增符号a+ a-类型添加代码*/ elseif (s
54、ym=plusplus) / 检测到后置 +符号 gendo(lit,0,1); gendo(lod,lev-tablei.level,tablei.adr); /* 找到变量地址并将其值入栈*/ gendo(opr,0,2); / 执行加操作,if (i!=0) gendo(sto,lev-tablei.level,tablei.adr); getsymdo; elseif (sym=minusminus) / 检测到后置 - 符号 gendo(lod,lev-tablei.level,tablei.adr); /* 找到变量地址并将其值入栈*/ gendo(lit,0,1); gendo(
55、opr,0,3); / 执行减操作,if (i!=0) gendo(sto,lev-tablei.level,tablei.adr); getsymdo; 情况 2 对于 + -前置的需要添加因子开始符号:facbegsysplusplus=true ; /* 增加符号 +开始因子 plusplus*/ facbegsysminusminus=true ; /* 增加符号 - 开始因子 minusminus*/ /*前置自增符号+a - -a 类型添加代码*/ if (sym=plusplus) getsymdo; if (sym=ident) / 后面跟的是变量 i=position(id,
56、*ptx); if (i=0) error(11); else if (tablei.kind!=variable) /+ 后没跟变量,出错 error(12); i=0; else/+ 后跟变量, 处理生成中间代码 if (tablei.kind=variable) gendo(lod,lev-tablei.level,tablei.adr);/ 先取值到栈顶gendo(lit,0,1); / 将值为入栈gendo(opr,0,2); / 加法,即 +1,栈顶加次栈顶gendo(sto,lev-tablei.level,tablei.adr);/ 出栈取值到内存getsymdo; elsei
57、f (sym=minusminus) getsymdo; if (sym=ident) / 后面跟的是变量 i=position(id,*ptx); if (i=0) error(11); else if (tablei.kind!=variable) /-后没跟变量,出错 error(12); i=0; else/-后跟变量, 处理生成中间代码 if (tablei.kind=variable) / 后跟变量 gendo(lod,lev-tablei.level,tablei.adr);/ 先取值到栈顶gendo(lit,0,1); / 将值为入栈gendo(opr,0,3); / 加法,即 -1,栈顶减次栈顶gendo(sto,lev-tablei.level,tablei.adr);/ 出栈取值到内存getsymdo; (2)作为因子的时候也有两种情形考虑:添加 int factor(bool *fsys, int *ptx,int lev) 函数如下:/*如果因子可能出现b:=a+或b:=a- 类型的处理 */if (sym=plusplus) gendo(lit,lev-tablei.level,1); / 将值为入栈gendo(opr,lev-tablei.level,2); / 加法,即 +1,栈顶加次栈
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 真石漆的施工方案
- 管道阴极保护施工方案
- 二零二五年度梁上打孔作业风险控制免责合同
- 二零二五年度金融服务合同价款调整与信用风险防范
- 二零二五年度武汉房屋租赁合同纠纷处理办法
- 二零二五年度足疗店连锁经营授权管理合同
- 二零二五年度能源消耗监控系统维保及节能服务合同
- 二零二五年度羊群代放牧与绿色食品生产协议
- 二零二五年度二零二五年度承重墙拆除工程安全生产责任承诺书
- 普通高等学校就业协议书(2025年度)-金融服务业人才输送协议
- 国能辽宁北票 200MW 风力发电项目地质灾害危险性评估报告
- 江苏省常州市教育学会2023-2024学年下学期八年级数学考试卷
- DZ∕T 0214-2020 矿产地质勘查规范 铜、铅、锌、银、镍、钼(正式版)
- 2024年瓦斯爆炸事故专项应急演练桌面推演脚本
- 2024年辽宁大连中远海运川崎船舶工程有限公司招聘笔试参考题库含答案解析
- 《单层厂房钢结构》
- 八年级下册二次根式作业设计
- 人音版二年级上册第六课《跳起舞》 单元作业设计
- 第43讲闭合电路欧姆定律(讲义)
- (2024年)面神经炎课件完整版
- 在社区结对共建签约仪式上的讲话3篇
评论
0/150
提交评论