编译原理龙书第二版第五章习题题解(部分)

5.1节

5.1.1中是自底向上语法树,5.1.2和5.1.3是自顶向下语法树

5.1.1

对于图 5-1 中的 SDD,给出下列表达式对应的注释语法分析树

1)(3+4)*(5+6)n

2)1*2*3*(4+5)n

3)(9+8*(7+6)+5)*4n

5.1.2

扩展图 5-4 中的 SDD,使它可以像图 5-1 所示的那样处理表达式

 产生式语法规则
1)L->EnL.val=E.val
2)E->TE'E'.inh = T.val
E.val = E'.syn
3)E'->+TE1'E1'.inh = E'.inh + T.val
E'.syn = E1'.syn
4)E' -> εE'.syn = E'.inh
5)T->FT'T'.inh = F.val
T.val = T'.syn
6)T'->*FT1'T1'.inh = T'.inh * F.val
T'.syn = T1'.syn
7)T' -> εT'.syn = T'.inh
8)F->(E)F.val = E.val
9)F -> digitF.val = digit.lexval

5.1.3

使用你在练习 5.1.2 中得到的 SDD,重复练习 5.1.1

1)(3+4)*(5+6)n

2)1*2*3*(4+5)n

3)略,感觉这题都差不多。

5.2节

5.2.1

图 5-7 中的依赖图的全部拓扑顺序有哪些

最后四位必须是6、7、8、9

保持1、3、5和2、4内部顺序,这两集合可以相互排列插入,但是必须保证序列135和24,不需要135挨在一起(24同理)。

所以有

[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
[ 1, 2, 3, 5, 4, 6, 7, 8, 9 ],
[ 1, 2, 4, 3, 5, 6, 7, 8, 9 ],
[ 1, 3, 2, 4, 5, 6, 7, 8, 9 ],
[ 1, 3, 2, 5, 4, 6, 7, 8, 9 ],
[ 1, 3, 5, 2, 4, 6, 7, 8, 9 ],
[ 2, 1, 3, 4, 5, 6, 7, 8, 9 ],
[ 2, 1, 3, 5, 4, 6, 7, 8, 9 ],
[ 2, 1, 4, 3, 5, 6, 7, 8, 9 ],
[ 2, 4, 1, 3, 5, 6, 7, 8, 9 ]

5.2.2

对于图 5-8 中的 SDD,给出下列表达式对应的注释语法分析树:

1)int a,b,c

2)float w,x,y,z

5.2.3

假设我们有一个产生式 A -> BCD。A, B, C, D 这四个非终结符号都有两个属性,综合属性 s 和继承属性 i。对于下面的每组规则,指出(1)这些规则是否满足 S 属性定义的要求(2)这些规则是否满足 L 属性定义的要求(3)是否存在和这些规则一致的求值过程? (这第三问没看懂)

1)A.s = B.i + C.s

(1)否。因为有继承属性i;(2)是;(3)存在

2)A.s = B.i + C.s , D.i = A.i + B.s

(1)否。因为有继承属性i;(2)是;(3)存在

3)A.s = B.s + D.s

(1)是;(2)是;(3)存在

4)A.s = D.i , B.i = A.s + C.s , C.i = B.s , D.i = B.i + C.i

(1)否。因为有继承属性i;(2)否。因为B.i依赖于其右兄弟值C.s;(3)不存在

5.2.4

 产生式语义规则
1)S->L1.L2

L1.side=left

L2.side=right

S.val=L1.val+L2.val

2)S->L

L.side=left

S.val=L.val

3)L->L1B

L1.side=L.side

L.len=L1.len+1

L.val=(L.side==left)?L1.val*2+B.val:L1.val+B.val*2^(-L.len)

4)L->B

L.len=1

L.val=(L.side==left)B.val:B.val/2

5)B->0B.val=0
6)B->1B.val=1

side为继承属性,当为left时表示在小数点左边,当为right时,表示在小数点右边。

val为综合属性,表示值

length为综合属性表示结点包含二进制串长度

5.2.5

为练习 5.2.4 中描述的文法和翻译设计一个 S 属性的 SDD。

 产生式语义规则
1)S -> L1.L2S.val = L1.val + L2.val/L2.f
2)S -> LS.val = L.val
3)L -> L1BL.val = L1.val*2 + B.val
L.f = L1.f * 2
4)L -> BL.val = B.val
L.f = 2
5)B -> 0B.val = 0
6)B -> 1B.val = 1

f为综合属性,若小数点后有n位,则其值为2^n。

5.3节

5.3.1

下面是涉及运算符 + 和整数或浮点运算分量的表达式的文法。区分浮点数的方法是看它有无小数点。

E -> E + T | T
T -> num.num | num

1)给出一个 SDD 来确定每个项 T 和表达式 E 的类型

 产生式语义规则
1)E -> E1 + TE.type = E1.type === float || T.type === float ? float : int
2)E -> TE.type = T.type
3)T -> num.numT.type = float
4)T -> numT.type = int

2)扩展这个得到的 SDD,使得它可以把表达式转换成为后缀表达式。使用一个单目运算符 intToFloat 把一个整数转换为相等的浮点数。

 产生式语义规则
1)E -> E1 + T

if(E1.type==int && T.type==int)

  E.type=int;

else

  E.type=float;

  if(E1.type==float && T.type==int)

    T.val=intToFloat(T.val);

  else if(E1.type==int && T.type==float)

    E1.val=intToFloat(E1.val);

 

E.val=E1.val || T.val || '+'

2)E -> T

E.type = T.type

E.val=T.val

3)T -> num.num

T.type = float

T.val=num.lexval

4)T -> num

T.type = int

T.val=num.lexval

5.3.2

给出一个 SDD,将一个带有 + 和 * 的中缀表达式翻译成没有冗余括号的表达式。比如因为两个运算符都是左结合的,并且 * 的优先级高于 +,所以 ((a*(b+c))*(d)) 可翻译为 a*(b+c)*d

产生式语义规则
E->E1+E2

E.op=‘+’

E.val=E1.val || '+' || E2.val

E->E1*E2

E.op=‘*’

E.val=E1.val || '*' || E2.val

E->(E1)

E.op=null

E.val=E1.val

E->(E1)+(E2)

E.op=‘+’

E.val=E1.val || '+' || E2.val

E->E1+(E2)

E.op=‘+’

E.val=E1.val || '+' || E2.val

E->(E1)+E2

E.op=‘+’

E.val=E1.val || '+' || E2.val

E->(E1)*(E2)

E.op='*'

if(E1.op=='+'&&E2.op=='+')

  E.val='(' || E1.val || ')*(' || E2.val || ')'

else if(E1.op=='+'&&E2.op!='+')

  E.val='(' || E1.val || ')*' || E2.val

else if(E1.op1='+'&&E2.op=='+')

  E.val=E1.val || '*(' || E2.val || ')'

else

  E.val=E1.val || '*' || E2.val 

E->E1*(E2)

E.op='*'

if(E2.op=='+')

  E.val=E1.val || '*(' || E2.val || ')'

else

  E.val=E1.val || '*' || E2.val 

E->(E1)*E2

E.op='*'

if(E2.op=='+')

  E.val='(' || E1.val || ')*' || E2.val

else

  E.val=E1.val || '*' || E2.val 

E->id

E.op=null

E.val=id

5.3.3

给出一个 SDD 对 x*(3*x+x*x) 这样的表达式求微分。表达式中涉及运算符 + 和 * 、变量 x 和常量。假设不进行任何简化,也就是说,比如 3*x 将被翻译为 3*1+0*x。

产生式语义规则
E->E1+E2

E.self=E1.self || ‘+’ || E2.self

E.differential=E1.differential || '+' || E2.differential

E->E1*E2

E.self=E1.self || '*' || E2.self

E.differential=E1.differential || ‘*’ || E2.self || '+' ||E1.self|| '*' || E2.differential

E->(E1)

E.self=E1.self

E.differential=E1.differential

E->num

E.self->num

E.differential=0

E->id

E.self=id

E.differential=1

5.4节

5.4.1

5.4.2

改写下面的 SDT:

A -> A {a} B | A B {b} | 0
B -> B {c} A | B A {d} | 1

使得基础文法变成非左递归的。 这里,a、b、c和d是语义动作,0和1是终结符号。

A -> 0 A'

A'-> {a}BA' | B{b}A'|Σ

B ->1B'

B' -> {c}AB' | A{d}B'|Σ

5.4.3

下面的 SDT 计算了一个由 0 和 1 组成的串的值。它把输入的符号串当做正二进制数来解释。

B -> B1 0 {B.val = 2 * B1.val}
   | B1 1 {B.val = 2 * B1.val + 1}
   | 1 {B.val = 1}

改写这个 SDT,使得基础文法不再是左递归的,但仍然可以计算出整个输入串的相同的 B.val 的值。

消除左递归后

B->1 B'

B'.inh=1

B.val=B'.val

B'->0 B1'

B1'.inh=2*B'.inh

B'.val=B1'.val

B'->1 B1'

B1'.inh=2*B'.inh+1

B'.val=B1'.val

B'->ΣB'.val=B'.inh

SDT

B->1 {B'.inh=1;} B' {B.val=B'.val}
B'->{B1'.inh=2*B'.inh} 0 {B1'.inh=B1'.inh+0}  B1' {B'.val=B1'.val}
B'->{B1'.inh=2*B'.inh} 1 {B1'.inh=B1'.inh+1}  B1' {B'.val=B1'.val}
B'->Σ {B'.val=B'.inh}

5.4.4

为下面的产生式写出一个和例 5.19 类似的 L 属性 SDD。这里的每个产生式表示一个常见的 C 语言那样的控制流结构。你可能需要生成一个三地址语句来跳转到某个标号 L,此时你可以生成语句 goto L。

1) S -> if ( C ) S1 else S2

L1 = new()
L2 = new()
C.true = L1
C.false = L2  
S1.next = S.next
S2.next = S.next
S.code = C.code || label || L1 || S1.code || label || L2 || S2.code

2) S -> do S1 while ( C )

L1 = new()
C.true = L1
S.code = label || L1 || S1.code || C.code

3) S -> '{' L '}'; L -> L S | ε(这个不写了)

请注意,列表中的任何语句都可能包含一条从它的内部跳转到下一个语句的跳转指令,因此简单地为各个语句按顺序生成代码是不够的。

5.4.5

按照例 5.19 的方法,把在练习 5.4.4 中得到的各个 SDD 转换成一个 SDT。

1)

S -> if (     {L1 = new(); L2 = new();C.true = L1;C.false = L2  }   
     C )      {S1.next = S.next;S2.next = S.next}
     S1 else
     S2      {S.code = C.code || label || L1 || S1.code || label || L2 || S2.code}

2)

S -> do           {L1 = new();} 
     S1 while (  {C.true = L1;}
     C )          {S.code = label || L1 || S1.code || C.code}

5.4.6

修改图 5.25 中的 SDD,使它包含一个综合属性 B.le,即一个方框的长度。两个方框并列后得到的方框的长度是这两个方框的长度和。然后把你的新规则加入到图 5.26 中 SDT 的合适位置上。

SDD

产生式语义规则
1)S->BB.ps = 10
2) B->B1B2

B1.ps=B.ps

B2.ps=B.ps

B.le=B1.le+B2.le

B.ht=max(B1.ht,B2.ht)

B.dp=max(B1.dp,B2.dp)

3) B->B1 sub B2

B1.ps = B.ps

B2.ps = 0.7 x B.ps

B.le=B1.le+B2.le

B.ht = max(B1.ht, B2.ht - 0.25 x B.ps)

B.dp = max(B1.dp, B2.dp + 0.25 x B.ps)
4) B->(B1)

B1.ps = B.ps

B.le=B1.le

B.ht = B1.ht

B.dp = B1.dp
5) B -> text

B.ht = getHt(B.ps, text.lexval)

B.dp = getDp(B.ps, text.lexval)

B.le=getLe(B.ps,text.lexval)

SDT

产生式                              语义动作

1)S->                            {B.ps = 10;} 

            B

2) B->                             {B1.ps=B.ps;}

           B1                        {B2.ps=B.ps}

           B2                        {B.le=B1.le+B2.le;

                                         B.ht=max(B1.ht,B2.ht);

                                         B.dp=max(B1.dp,B2.dp);}

3) B->                             {B1.ps = B.ps}

           B1 sub                 {B2.ps = 0.7 x B.ps}

           B2                        {B.le=B1.le+B2.le;

                                         B.ht = max(B1.ht, B2.ht - 0.25 x B.ps);

                                         B.dp = max(B1.dp, B2.dp + 0.25 x B.ps);}

4) B->(                            {B1.ps = B.ps}

          B1)                        {B.le=B1.le;

                                        B.ht = B1.ht;

                                        B.dp = B1.dp;} 

5) B -> text                     {B.ht = getHt(B.ps, text.lexval);

                                        B.dp = getDp(B.ps, text.lexval);

                                        B.le=getLe(B.ps,text.lexval);}

5.4.7

修改图 5.25 中的 SDD,使它包含上标,用方框之间的运算符 sup 表示。如果方框 B2 是方框 B1 的一个上标,那么将 B2 的基线放在 B1 的基线上方,两条基线的距离是 0.6 乘以 B1 的大小。把新的产生式和规则加入到图 5.26 的 SDT 中去。

SDD(该结果是在5.4.6的基础上加的,没有去掉5.4.6的要求属性)

产生式语义规则
1)S->BB.ps = 10
2) B->B1B2

B1.ps=B.ps

B2.ps=B.ps

B.le=B1.le+B2.le

B.ht=max(B1.ht,B2.ht)

B.dp=max(B1.dp,B2.dp)

3) B->B1 sub B2

B1.ps = B.ps

B2.ps = 0.7 x B.ps

B.le=B1.le+B2.le

B.ht = max(B1.ht, B2.ht - 0.25 x B.ps)

B.dp = max(B1.dp, B2.dp + 0.25 x B.ps)
4) B -> B1 sup B2

B1.ps = B.ps

B2.ps = 0.6 * B.ps

B.le=B1.le+B2.le

B.ht = max(B1.ht, B2.ht + 0.6 * B.ps)

B.dp = max(B1.dp, B2.dp - 0.6 * B.ps) 
5) B->(B1)

B1.ps = B.ps

B.le=B1.le

B.ht = B1.ht

B.dp = B1.dp
6) B -> text

B.ht = getHt(B.ps, text.lexval)

B.dp = getDp(B.ps, text.lexval)

B.le=getLe(B.ps,text.lexval)

SDT

产生式                              语义动作

1)S->                            {B.ps = 10;} 

            B

2) B->                             {B1.ps=B.ps;}

           B1                        {B2.ps=B.ps}

           B2                        {B.le=B1.le+B2.le;

                                         B.ht=max(B1.ht,B2.ht);

                                         B.dp=max(B1.dp,B2.dp);}

3) B->                             {B1.ps = B.ps}

           B1 sub                 {B2.ps = 0.7 x B.ps}

           B2                        {B.le=B1.le+B2.le;

                                         B.ht = max(B1.ht, B2.ht - 0.25 x B.ps);

                                         B.dp = max(B1.dp, B2.dp + 0.25 x B.ps);}

4) B->                             {B1.ps = B.ps}

           B1 sup                 {B2.ps = 0.6 x B.ps}

           B2                        {B.le=B1.le+B2.le;

                                         B.ht = max(B1.ht, B2.ht + 0.6 x B.ps);

                                         B.dp = max(B1.dp, B2.dp - 0.6 x B.ps);}

5) B->(                            {B1.ps = B.ps}

          B1)                        {B.le=B1.le;

                                        B.ht = B1.ht;

                                        B.dp = B1.dp;} 

6) B -> text                     {B.ht = getHt(B.ps, text.lexval);

                                        B.dp = getDp(B.ps, text.lexval);

                                        B.le=getLe(B.ps,text.lexval);}

5.5节

5.5.1

按照 5.5.1 节的风格,将练习 5.4.4 中得到的每个 SDD 实现为递归下降的语法分析器。

S -> if ( C ) S1 else S2

string S(label next)
{   
    string Ccode, S1code, S2code;
    label L1, L2;
    if(current input==token while)
    {   
        advance input;
        check '(' is next on the input, and advance;
        L1 = new();
        L2 = new();
        Ccode = C(L1, L2);
        check ')' is next on the input, and advance;
        S1code = S(next);
        check else;
        S2code = S(next);
        return (Ccode || "label" || L1 || S1code || "label" || L2 || S2code);
    }   
    else
        // other statement types
}

5.5.2

按照 5.5.2 节的风格,将练习 5.4.4 中得到的每个 SDD 实现为递归下降的语法分析器。

S -> if ( C ) S1 else S2

void S(label next)
{   
    label L1, L2;
    if(current input==token while)
    {   
        advance input;
        check '(' is next on the input, and advance;
        L1 = new();
        L2 = new();
        C(L1, L2);
        check ')' is next on the input, and advance;
        printf("label", L1);
        S(next);
        check else;
        printf("label", L2);
        S(next);
    }   
    else
        // other statement types
} 

5.5.3

按照 5.5.3 节的风格,将练习 5.4.4 中得到的每个 SDD 和一个 LL 语法分析器一起实现。它们应该边扫描输入边生成代码。

S -> if ( C ) S1 else S2

S
next=x
if(ActionC)ActionS1elseActionS2
  

L1=?

L2=?

fasle=?

true=?

 al1=?next=x al2=?next=x

L1=new()

L2=new()

stack[top-1].false = L2

stack[top-1].true = L1

stack[top-3].al1 = L1

stack[top-5].al2 = L2

 

   C)ActionS1elseActionS2
  

 

fasle=L2

true=L1

 al1=L1next=x al2=L2next=x

对于S1前面的Action

printf("label", al1)

对于S2前面的Action

printf("label", al2)

5.5.4

按照 5.5.3 节的风格,将练习 5.4.4 中得到的每个 SDD 和一个 LL 语法分析器一起实现,但是代码(或者指向代码的指针)存放在栈中。

S -> if ( C ) S1 else S2

变为S -> if ( X C ) Y S1 else Z S2

X-> ε; Y-> ε; Z-> ε;

if(XC)YS1elseActionS2
S.next  

C.true
C.false
L1
L2

C.code

 S1.nextS1.code S2.nextS2.code

L1 = new()

L2 = new()

C.true = L1

C.false = L2

tempCode = C.code || "label" || stack[top-4].L1 || stack[top-3].code || "label" || stack[top-4].L2 || stack[top].code

top -=9

stack[top].code = tempCode


5.5.5

按照 5.5.4 节的风格,将练习 5.4.4 中得到的每个 SDD 和一个 LR 语法分析器一起实现。

1)

S->if (C)               {backpatch(C.truelist, nextInstr);}

      S1 else N S2  {backpatch(C.truelist, N.instr+1);

                              S.nextlist=merge(S1.nextlist,S2.nextlist);

                              AddElementItem(S.nextlist,N.instr)}

N->Σ                   {N.instr=nextInstr;

                            gen('goto_');}

2)

S->do M S1 while(   {backpatch(S1.truelist, nextInstr);}

      C)                       {backpatch(C.truelist, M.instr);

                                  S.nextlist=C.falselist;}

M->Σ                         {M.instr=nextInstr; }

 

  • 36
    点赞
  • 181
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值