现在的位置: 首页 > 综合 > 正文

《编译原理-龙书》练习第2章

2018年05月04日 ⁄ 综合 ⁄ 共 2852字 ⁄ 字号 评论关闭

第2章 一个简单的语法制导翻译器

2.2 语法定义

主要描述了“上下文无关文法”

2.2.1 

1)

S1 = aa+

S2 = S1a*

2)              *

          +

a  a        a

3)该文法生成的语言是由+和*组成的后缀表达式,怎么证明呢?

2.2.2 同不懂怎么证明

1)前面n个0后面n个1组成的串

2)+/-组成的关于a计算的前缀表达式

3)空串或成对出现的单个或嵌套括号组成的表达式

4)空串或a和b组成的任意表达式

5)由+连接起来的1个或多个a,可以加括号,每个a后面可以有0个或多个*

2.2.3

1)没有二义性

2)有,跟例2.1中语法一样

3)没有

4)有,ab可以随意结合

5)有,S+S和SS无法确定如何结合

2.2.4

1)S -> SS+|SS-|SS*|SS/|a

2)left -> left,expr | expr

3)right -> expr,right|expr

4)这道题中文版翻译有误,应该将书中“标识符”去掉。

expr -> expr+term | expr-term|term

term -> term*factor | term/factor|factor

factor -> digits

digits -> digitdigit|digit

5)+ -单目运算符优先级应该最高

expr -> expr+term1 | expr-term1|term1
term1 -> term1*term2 | term1/term2|term2

term2 -> -factor | +factor|factor

factor -> digits

digits -> digitdigit|digit

2.2.5 根据提示,采用数学归纳法证明如下:

如果节点数是1,显然 11 1001都能被3整除

如果节点数是2,110 10010 1111 10011001都能被3整除

假设节点数小于等于n的情况所有二进制串都能被3整除,则n+1个节点的所有串可能有以下情况

 1.节点数为n的串后面加个0,记为Sn0 = Sn*2,显然能被3整除

 2.SiSj,SiSj分别表示节点数为i和j的串,则SiSj = Si*2^j+Sj,根据假设,Si和Sj都能被3整除,所以SiSj能被3整除

2.2.6

背景知识 : http://baike.baidu.com/view/42061.htm

首先需要知道罗马数字的表示方法

I、V、X、L、C、D、M

分别表示1 5 10 50 100 500 1000

罗马数字上下文无关文法如下:

number -> digit digit| digit

digit -> I | V | X | L | C | D | M

2.3语法制导翻译

本小节介绍的翻译方案有2种,图2-10中的字符串属性和图2-15中的打印方式,我们练习的时候采用第一种,第二种类似
练习中都考虑到了运算符优先级,比书中稍微复杂一些

2.3.1同图2-10,只是前2行不同:

expr->expr1+term       expr.t = '+'|expr1.t|term.t

expr->expr1-term       expr.t = '-'|expr1.t|term.t

expr->term

term->term1*factor    term.t = '*'|term1.t|factor.t

term->term1/factor    term.t = '/'|term1.t|factor.t

term->factor

9-5+2

                                        expr.t =  +-952

                   expr.t = -95            +             factor.t = 2

factor.t = 9       -       factor.t = 5
9-5*2

                       expr.t =  -9*52

factor.t = 9            -             expr.t = *52

                             factor.t = 5       -       factor.t = 2

2.3.2 跟2.3.1差不多

2.3.3 求解

2.3.4 求解

2.3.5 可以分2步实现,先转成中缀,然后转成前缀

2.4 语法分析

2.4.1 

1)

void S()
{
switch( lookahead )
{
case +: 
match(+); S(); S(); break;
case -:
 match(-); S(); S(); break;
case a: 
match(a); break;
default:report("syntax error");
}
}

2)这种情况就不要用switch了,if比较适合,要注意消除递归,消除方法是在开始加一系列判断,错误处理比较复杂,下面没加,如果要加该怎么处理呢??

void S()
{
if(lookahead==NULL)
return;
if(lookahead=='(' && lookahead+1==')')
{match('('); match(')');return;S()math('(')S()match(')')S()}

3)两个产生式的FIRST都是0,需要注意,不过相比较2),容易实现

void S()
{
	if(lookahead==0)
	{
	match(0);
	if(lookahead!=1)
	S();
	match(1);
	}
	else
	report("syntax error");
}



2.6 词法分析

这一节相对容易懂一些,练习也比较简单

2.6.1

1)类似判断数字,连续读入 ‘/’ ‘/’认为是注释

2)类似判断数字,读入‘/’ ‘*’ 以后判断 ‘*’ ‘/’,否则认为是错误

2.6.2 只需要再scan函数中添加类似数字,字母的判断即可

2.6.3 只需在scan判断数字的区域中添加相关代码即可

2.7

57页的top:如果把符号表看成一颗数,top表示当前使用的叶子,书中57页第2行符号表链的顶部表示的就是这个意思

2.8 生成中间代码

2.8.1
package inter;
import symbols.*;

public class For extends Stmt {

   Expr expr1;
   Expr expr2;
   Expr expr3;
   Stmt stmt;

   public If(Expr x1, Expr x2, Expr x3, Stmt s) {
      expr1 = x1;
      expr2 = x2;
      expr3 = x3;
      stmt = s;
      if( expr2.type != Type.Bool ) expr.error("boolean required in For");
   }

   public void gen(int b, int a) {
       int label1 = newlabel();
       int label2 = newlavel();
       emit(expr1.toString());
       emit(label1+":");
       Expr n=expr1.rvalue();
       emit("ifFalse"+n.toString()+"goto"+label2)
       stmt.gen();
       emit(expr3.toString());
       emit("goto"+label1);
       emit(label2+":");
   }
}
2.8.2
如果没有布尔类型,可能是根据表达式计算结果的类型分类进行判断,如果势int判断是否等于0,如果字符串判断是否为空,如果指针判断是否为空指针


抱歉!评论已关闭.