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->En | L.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 -> digit | F.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->0 | B.val=0 |
6) | B->1 | B.val=1 |
side为继承属性,当为left时表示在小数点左边,当为right时,表示在小数点右边。
val为综合属性,表示值
length为综合属性表示结点包含二进制串长度
5.2.5
为练习 5.2.4 中描述的文法和翻译设计一个 S 属性的 SDD。
产生式 | 语义规则 | |
1) | S -> L1.L2 | S.val = L1.val + L2.val/L2.f |
2) | S -> L | S.val = L.val |
3) | L -> L1B | L.val = L1.val*2 + B.val L.f = L1.f * 2 |
4) | L -> B | L.val = B.val L.f = 2 |
5) | B -> 0 | B.val = 0 |
6) | B -> 1 | B.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 + T | E.type = E1.type === float || T.type === float ? float : int |
2) | E -> T | E.type = T.type |
3) | T -> num.num | T.type = float |
4) | T -> num | T.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->B | B.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->B | B.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 | ( | Action | C | ) | Action | S1 | else | Action | S2 |
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 | ) | Action | S1 | else | Action | S2 | |||
| fasle=L2 true=L1 | al1=L1 | next=x | al2=L2 | next=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 | ( | X | C | ) | Y | S1 | else | Action | S2 |
S.next | C.true | C.code | S1.next | S1.code | S2.next | S2.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; } |