您的位置:首页 > 其它

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

2012-12-03 22:51 190 查看

第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,如果字符串判断是否为空,如果指针判断是否为空指针
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: