5.6程序流控制语句的翻泽 在源程序中,控制语句用于实现程序流程 的控制。一般而言,程序流程控制可大致 分为顺序结构(如复合语句)、分枝结构 (如if条件语句和实现多分枝的case语句 等)、循环结构(如for循环、while循环、 repeat循环等等)三类。另外,GOTO语句 也是一类常见改变流程的控制语句。下面, 我们将对常见的一些控制结构的翻译进行 讨论
5.6 程序流控制语句的翻译 • 在源程序中,控制语句用于实现程序流程 的控制。一般而言,程序流程控制可大致 分为顺序结构(如复合语句)、分枝结构 (如if条件语句和实现多分枝的case语句 等)、循环结构(如for循环、while循环、 repeat循环等等)三类。另外,GOTO语句 也是一类常见改变流程的控制语句。下面, 我们将对常见的一些控制结构的翻译进行 讨论
5.6.1常见控制猪构的禄 程序设计理论已证明,任何程序均可由序列结 构、条件分枝结构和while循环三种结构等价 地表示。因此,我们先讨论这三类结构的翻译。 这三类结构可用如下的文法描述: 1.S→if E then S(1) if E then S(1)else S(2) 3. while E do S(1) 4. I begin L end (5.8) 5. IA 67 L→L;S IS
5.6.1 常见控制结构的翻译 • 程序设计理论已证明,任何程序均可由序列结 构、条件分枝结构和while循环三种结构等价 地表示。因此,我们先讨论这三类结构的翻译。 这三类结构可用如下的文法描述: 1. S→ if E then S(1) 2. | if E then S(1) else S(2) 3. | while E do S(1) 4. | begin L end (5.8) 5. | A 6. L→L ;S 7. | S
有关控制结构文法的注解 上述文法中,非终结符S、L、A分别代表语 句、语句串和赋值语句,E代表布尔表达式 此外,由于f语句可能带来二义性,我们约 定每一个else总是与其前离它最近的尚未得 到匹配的then相匹配。在文法(5.8)中,为 了区别同一产生式中不同位置上的同名文 法符号,我们为其增加了上标
有关控制结构文法的注解 • 上述文法中,非终结符S、L、A分别代表语 句、语句串和赋值语句,E代表布尔表达式。 此外,由于if语句可能带来二义性,我们约 定每一个else总是与其前离它最近的尚未得 到匹配的then相匹配。在文法(5.8)中,为 了区别同一产生式中不同位置上的同名文 法符号,我们为其增加了上标
条件语句的处理方法 ·在5.5节的图5-5中,我们已经给出了if语句和while 语句的代码结构。 ·布尔表达式E具有两个属性:E.TC与E.FC,用来 分别指示E的真链和假链的链首。 ·当E出现在条件语句if-then-else中时,根据条件语 句的语义,当语法分析器扫视到then时,E的真 出口已经确定,此时即可用NXQ对E的真链进行 回填;而当扫视到else时,即可用NXQ对E的假 链进行回填
条件语句的处理方法 • 在5.5节的图5-5中,我们已经给出了if语句和while 语句的代码结构。 • 布尔表达式E具有两个属性:E.TC与E.FC,用来 分别指示E的真链和假链的链首。 • 当E出现在条件语句if-then-else中时,根据条件语 句的语义,当语法分析器扫视到then时, E的真 出口已经确定,此时即可用NXQ对E的真链进行 回填;而当扫视到else时,即可用NXQ对E的假 链进行回填
条件语句的翻译结构 注意, 动作2中 的内容与教材中 因此,if-then-else结构的翻译文法可写为: 的内容略有不同, 但功能相同。 S→if E then BackPatch(E.TC,NXQ);/*动作1:回填Ey链*/} S(1)else {intT=GEN(j,0,0,0);/*S(1)的常规出口,由此转出所在 的条件语句;注意:此时NXQ在GEN函数内被加1*/ T=Merge(T,S(1).Chain); BackPatch(E.FC,NXQ)i/*动作2:将S的常规出口与 S程序结构内的其它出口(已在的翻译过程中拉成链, 由S).Chain,属性指示)合并成一个链;并以S2的第一 条四元式的序号回填E的假链*/ S(2){S.Chain=Merge(T,S(2).Chain); /*动作3:将的S2)出口与S2)的出口合并,作为S的出口*/
条件语句的翻译结构 因此,if-then-else结构的翻译文法可写为: S→if E then {BackPatch(E.TC,NXQ);/*动作1:回填E的真链*/} S(1) else {int T= GEN(j,0,0,0); /*S(1)的常规出口,由此转出所在 的条件语句;注意:此时NXQ在GEN函数内被加1 */ T=Merge(T, S(1) .Chain); BackPatch(E.FC,NXQ); /*动作2:将S (1)的常规出口与 S (1)程序结构内的其它出口(已在的翻译过程中拉成链, 由S (1).Chain属性指示)合并成一个链;并以S (2)的第一 条四元式的序号回填E的假链*/ } S(2) {S.Chain=Merge(T, S(2) .Chain); /*动作3:将的S (2)出口与S (2)的出口合并,作为S的出口*/ } 注意,动作2中 的内容与教材中 的内容略有不同, 但功能相同
属性文法结构分析 ·从文法中可看出,产生式左部符号S的综合属性Chain是 经过两个语义动作(2和3)之后才最终确定的,在这两个动 作之间,还执行了语法分析动作(移进else,并移进和归 约出S(2)。 ·另外,在产生式右部符号之间插入语义动作,容易带来混 乱,它不易阅读,在具体的编译系统中也不易实现。 。 常见的编译系统中,往往希望将语义动作置于产生式中所 有文法符号的右侧.目的是使翻译按这样方式进行,当用 某产生式进行归约时,在完成了语法分析动作(归约)之后, 执行相应的语义动作(语义子程序),即使用$-属性波兰翻 译文法
属性文法结构分析 • 从文法中可看出,产生式左部符号S的综合属性Chain是 经过两个语义动作(2和3)之后才最终确定的,在这两个动 作之间,还执行了语法分析动作(移进else,并移进和归 约出S(2))。 • 另外,在产生式右部符号之间插入语义动作,容易带来混 乱,它不易阅读,在具体的编译系统中也不易实现。 • 常见的编译系统中,往往希望将语义动作置于产生式中所 有文法符号的右侧.目的是使翻译按这样方式进行,当用 某产生式进行归约时,在完成了语法分析动作(归约)之后, 执行相应的语义动作(语义子程序),即使用S-属性波兰翻 译文法
改造文法的两种途☑ ·对上述翻译文法进行改造的方法有二: 1.将所有出现在“中部”的动作符号(语义动作)用一新 的非终结符取而代之,并为其定义一个ε-产生式,所配 的语义动作即为原来的动作符。例如,(5.9)式可改写 为: S→if E then M1S四else M2S2,{U*动作3*乃 M,→e{U*动作1*乃 (5.10) M→8{/*动作2*乃 2.将原产生式“拆分”成若干个“小”产生式,拆分点就 设在每个动作符的出现处,以保证动作符均出现在最右 侧。例如,(5.9)可改写为: S→US2) {/*动作3*乃 U→T S()else {/*动作2*乃 (5.11) T→if E then {/*动作1*乃
改造文法的两种途径 • 对上述翻译文法进行改造的方法有二: 1.将所有出现在 “中部”的动作符号(语义动作)用一新 的非终结符取而代之,并为其定义一个ε-产生式,所配 的语义动作即为原来的动作符。例如,(5.9)式可改写 为: S→ if E then M1 S (1) else M2 S (2) {/*动作3*/} M1 → {/*动作1*/} (5.10) M2 → {/*动作2*/} 2.将原产生式“拆分”成若干个“小”产生式,拆分点就 设在每个动作符的出现处,以保证动作符均出现在最右 侧。例如,(5.9)可改写为: S → U S(2) {/*动作3*/} U → T S(1) else {/*动作2*/} (5.11) T → if E then {/*动作1*/}
两种文法改造方法的比轻 第一种方法轻简单,且对原文法的可读性影响不大,在 需插入的动作不多时,可采用此法。 。 但若使用此法过多,就会带来由于大量ε-产生式的引入 而产生新的文法冲突的问题,使语法分析无法进行。 ·因此,更好的方法是“拆分法”,经验表明,这种方法 基本上不会对原文法的语法分析带来影响,且产生式相 对“短”些,存取分析程序在栈中语义信息会更方便。 ·另外,从语义动作的描述角度来说,我们还可借助YACC 的描述方式,即用符号’$后跟一数字或’$来区分不同 的文法符号,从而无须再对同名符号冠以上标。 ·基于上述原因,以后的动作描述,将一律采用“拆分法
两种文法改造方法的比较 • 第一种方法较简单,且对原文法的可读性影响不大,在 需插入的动作不多时,可采用此法。 • 但若使用此法过多,就会带来由于大量ε-产生式的引入 而产生新的文法冲突的问题,使语法分析无法进行。 • 因此,更好的方法是“拆分法”,经验表明,这种方法 基本上不会对原文法的语法分析带来影响,且产生式相 对“短” 些,存取分析程序在栈中语义信息会更方便。 • 另外,从语义动作的描述角度来说,我们还可借助YACC 的描述方式,即用符号’$’后跟一数字或’$’来区分不同 的文法符号,从而无须再对同名符号冠以上标。 • 基于上述原因,以后的动作描述,将一律采用“拆分法
控制利语句的翻泽文法 现在,我们讨论(5.8)所给文法的翻译。我们将文法进行 改写(拆分),为便于理解,我们将原文法中的E、S、L、A 更名为Expr、Statement、Series和Assignment。 1.Condition-if Expr then {BackPatch($2.TC,NXQ); $$.Chain=$2.FC;} 当使用此产生式进行归约时,布尔表达式Ep的四元式序 列已经产生,并且then后的语句S的第一四元式序号已 能确定(即NXQ的值).因此,可用NXQ回填Expr的T链; 由于Exp的F链的去向未定,同时,因在执行归约动作时 Exp将从分析栈中弹出,所以其FC属性需保留下来, 因此它将作为Condition的一个综合属性Chain(整型, 描述某四元式序列链的链首地址(序号))传递上去,待 以后能确定地址时回填
控制语句的翻译文法 现在,我们讨论(5.8)所给文法的翻译。我们将文法进行 改写(拆分),为便于理解,我们将原文法中的E、S、L、A 更名为Expr、Statement、Series和Assignment。 1.Condition→ifExpr then {BackPatch($2.TC,NXQ); $$.Chain=$2.FC;} 当使用此产生式进行归约时,布尔表达式Expr的四元式序 列已经产生,并且then后的语句S的第一四元式序号已 能确定(即NXQ的值).因此,可用NXQ回填Expr的T链; 由于Expr的F链的去向未定,同时,因在执行归约动作时 Expr将从分析栈中弹出,所以其FC属性需保留下来, 因此它将作为Condition的一个综合属性Chain(整型, 描述某四元式序列链的链首地址(序号))传递上去,待 以后能确定地址时回填
控制语句的翻泽文法(续1) 2.Statement->Condition Statement [$$Chain=Merge($1.Chain,$2.Chain);} 此时,所翻译的是if-then语句结构,原条件语句的布尔表达 式EXpr的F链的去向应和then后的语句的出口一致,而归 约所得的语句Statement的出口尚未确定(因为该语句可 能是更复杂语句结构中的子语句),因此应将这两条链合 并成一个大链,待合适的时候回填。 这里,Statement的属性Chain用于描述本语句结构的所有 出口的链首
控制语句的翻译文法(续1) 2.Statement→ Condition Statement {$$.Chain=Merge($1.Chain, $2.Chain);} 此时,所翻译的是if-then语句结构,原条件语句的布尔表达 式Expr的F链的去向应和then后的语句的出口一致,而归 约所得的语句Statement的出口尚未确定(因为该语句可 能是更复杂语句结构中的子语句),因此应将这两条链合 并成一个大链,待合适的时候回填。 这里,Statement的属性Chain用于描述本语句结构的所有 出口的链首