Skip to content
Notes
GitHub

期末习题

问答

  • 简述 L-属性文法的定义;
  • 简述 S-属性文法的定义;
  • 简述句型的定义;
  • 简述文法 G[Z]\displaystyle{ G \left[ Z \right] } 所定义的语言的含义;
  • 简述素短语的定义。

文法

化简文法
SaABScCACdAbABcSAcCCBbABcSBCcScDeAEfAg\begin{aligned} S & \to a ABS \mid cCACd \\ A & \to bAB \mid cSA \mid cCC \\ B & \to bAB \mid cSB \\ C & \to cS \mid c \\ D & \to eA \\ E & \to fA \mid g \end{aligned}
解答
  • 没有推导式可以推导出 D,E\displaystyle{ D , E },因此删除包含 D,E\displaystyle{ D , E } 的产生式规则
  • B\displaystyle{ B } 会陷入无限递归,没有终止条件,将所有含有 B\displaystyle{ B } 的式子都删去
ScCACdAcSAcCCCcSc\begin{aligned} S & \to cCACd \\ A & \to cSA \mid cCC \\ C & \to cS \mid c \end{aligned}
试写出下列满足要求或产生下列语言的文法
  1.  {anbm,n>0,m>0 }\displaystyle{ \ \left\lbrace a ^{ n } b ^{ m } , n > 0 , m > 0 \ \right\rbrace }
  2. {0n111n,n1}\{0^n111^n,n \geqslant 1\}
解答

第一题

SABAaAaBbBb\begin{aligned} S & \to AB \\ A & \to aA \mid a \\ B & \to bB \mid b \end{aligned}

第二题(已修改)

SABA0A101B11\begin{aligned} S & \to AB \\ A & \to 0A1 \mid 01 \\ B & \to 11 \end{aligned}
试给出语言 L={WW(01)L=\{ W | W \in (0\mid1)^*, 且 W\displaystyle{ W } 不含两个相邻的 1 }\displaystyle{ 1 \ \rbrace } 的 LL(1) 文法
解答(已修改)
S0S1AεA0Sε\begin{aligned} S & \to 0 S \mid 1A \mid \varepsilon \\ A & \to 0S \mid \varepsilon \end{aligned}
First 集Follow 集
S{0, 1, ε\varepsilon}{#}
A{0, ε\varepsilon}{#}
预测分析表01#
SS0SS \to 0SS1AS \to 1ASεS \to \varepsilon
AA0SA \to 0SAεA \to \varepsilon

没有冲突,是 LL(1) 文法

终态 YVNY \notin V_\mathrm{N},有限自动机 M\displaystyle{ M }

δ(S,0)=Sδ(S,1)=Aδ(S,ε)=Yδ(A,0)=Sδ(A,ε)=Y\begin{aligned} \delta(S, 0)=S && \delta(S, 1)=A && \delta(S, \varepsilon)=Y \\ \delta(A, 0)=S && \delta(A, \varepsilon)=Y \end{aligned}

public/compile/compx667gyiio.svg

01
ε-Closure({S})={S,Y}\varepsilon \text{-Closure}(\{S\})=\{S, Y\}{S, Y}{A, Y}
{A, Y}{S, Y}\varnothing

public/compile/compx87hghfh51.svg

DFA

设计一个 DFA ,识别出所有的由 0、1 所成的串,要求:每一个 1 后边必须跟至少一个 0 。如: 0 是合法的。 010 也是合法的。但 01 是不合法的。

解答(已修改)

给出相应文法

Z0Z1A0A0Z0\begin{aligned} Z & \to 0Z \mid 1A \mid 0 \\ A & \to 0Z \mid 0 \end{aligned}

终态 YVNY \notin V_\mathrm{N},有限自动机 M\displaystyle{ M },其中

δ(Z,0)=Zδ(Z,1)=Aδ(Z,0)=Yδ(A,0)=Zδ(A,1)=δ(A,0)=Y\begin{aligned} \delta (Z, 0)=Z && \delta (Z, 1)= A && \delta (Z, 0)=Y \\ \delta (A, 0)=Z && \delta (A, 1)= \varnothing && \delta (A, 0)=Y \end{aligned}

public/compile/compxvbb.svg

01
ε-Closure({Z})\varepsilon \text{-Closure}(\{Z\}){Z, Y}{A}
{Z, Y}{Z, Y}{A}
{A}{Z, Y}\varnothing

public/compile/compxbghfg.svg

将下面的有限自动机确定并最小化

public/compile/compx56765gj.svg

解答
ab
ε-Closure({0})={0}\varepsilon \text{-Closure}(\{0\})=\{0\}{0, 1}{1}
{0, 1}{0, 1}{0, 1}
{1}\varnothing{0}

public/compile/compxtuhfu.svg

上图已经是确定化的最小有限自动机

LL(1)

有文法 G[S]\displaystyle{ G \left[ S \right] }
SSaSbSbSSε\begin{aligned} S & \to SaSb \\ S & \to bS \\ S & \to \varepsilon \end{aligned}

试给出 LL(1) 分析表,说明它是不是 LL(1) 文法

解答
First 集Follow 集
S{a, b, ε}{a, b, #}
LL(1) 分析表ab#
SSSaSbS \to SaSb
SεS \to \varepsilon
SbSS \to bS
SSaSbS \to SaSb
SεS \to \varepsilon
SεS \to \varepsilon

不是 LL(1) 文法

有文法 G[Z]\displaystyle{ G \left[ Z \right] }
ZBAAaAεBbBε\begin{aligned} Z & \to BA \\ A & \to aA \mid \varepsilon \\ B & \to bB \mid \varepsilon \end{aligned}

构造 LL(1) 分析表,写出句子 baa# 的分析过程

解答(已修改)
First 集Follow 集
Z{b, a, ε}{#}
A{a, ε}{#}
B{b, ε}{#, a}
LL(1) 分析表ab#
ZZBAZ \to BAZBAZ \to BAZBAZ \to BA
AAaAA \to aAAεA \to \varepsilon
BBεB \to \varepsilonBbBB \to bBBεB \to \varepsilon
步骤输入输出
1# Zbaa#
2# A Bbaa#ZBAZ \to BA
3# A B bbaa#BbBB \to bB
4# A Baa#
5# Aaa#BεB \to \varepsilon
6# A aaa#AaAA \to aA
7# Aa#
8# A aa#AaAA \to aA
9# A#
10##AεA \to \varepsilon
有文法 G[E]\displaystyle{ G \left[ E \right] }
EEE(E)()\begin{aligned} E \to EE \mid (E) \mid () \end{aligned}

证明该文法是二义性文法

解答

对于表达式 ()()()\displaystyle{ \left( \right) \left( \right) \left( \right) } 有不同的语法树

graph TD e1((E1)) --- e2((E2)) e1 --- e3((E3)) e2 --- e4((E4)) e2 --- e5((E5)) e3 --- k1["("] e3 --- k2[")"] e4 --- k3["("] e4 --- k4[")"] e5 --- k5["("] e5 --- k6[")"] ea((E1)) --- eb((E2)) ea --- ec((E3)) eb --- ka["("] eb --- kb[")"] ec --- ed((E4)) ec --- ee((E5)) ed --- kc["("] ed --- kd[")"] ee --- ke["("] ee --- kf[")"]
%%{init: {'theme':'dark'}}%% graph TD e1((E1)) --- e2((E2)) e1 --- e3((E3)) e2 --- e4((E4)) e2 --- e5((E5)) e3 --- k1["("] e3 --- k2[")"] e4 --- k3["("] e4 --- k4[")"] e5 --- k5["("] e5 --- k6[")"] ea((E1)) --- eb((E2)) ea --- ec((E3)) eb --- ka["("] eb --- kb[")"] ec --- ed((E4)) ec --- ee((E5)) ed --- kc["("] ed --- kd[")"] ee --- ke["("] ee --- kf[")"]

因此该文法是二义性文法

SLR(1)

有文法 G[S]\displaystyle{ G \left[ S \right] }
SS+SSaSε\begin{aligned} S & \to S + S \\ S & \to a \\ S & \to \varepsilon \end{aligned}

给出文法的 SLR(1) 分析表,说明它是不是 SLR(1) 文法

解答(已修改)

public/compile/compx9876h.svg

Follow(S) = {+, #}

状态ACTIONGOTO
^^a+#S
0s31
1s2acc
2s3/r4r4r43
3r2/s2r2
4r3r3

其中有单元格出现冲突,不是 SLR(1) 文法

有文法 G[S]\displaystyle{ G \left[ S \right] }
SaSSbSSε\begin{aligned} S & \to a S \\ S & \to b S \\ S & \to \varepsilon \end{aligned}

给出文法的 SLR(1) 分析表,说明它是不是 SLR(1) 文法

解答

public/compile/comp987yhj.svg

Follow(S) = {#}

状态ACTIONGOTO
^^ab#S
0s2/r4s4/r4r41
1acc
2s2/r4s3/r4r43
3r2
4s2/r4s3/r4r45
5r3

是 SLR(1) 文法

算符优先文法

有文法 G[S]\displaystyle{ G \left[ S \right] }
SL,(S)LSi\begin{aligned} S & \to L, (S) \\ L & \to S \mid i \end{aligned}

给出算符优先关系表,说明该文法是不是算符优先文法。给出算符优先函数。

解答
FirstVT(X)LastVT(X)
S, i)
Li ,i )
  1. 第一条产生式规则
  • (S)\displaystyle{ \left( S \right) } 可知 ( \doteq )
  • ,(\displaystyle{ , \left( \right. } 可知 , \doteq (
  • (S)\displaystyle{ \left( S \right) } 可知 ( FirstVT(S)\lessdot \text{FirstVT}(S),即 ( \lessdot ,( \lessdot i;同时 LastVT(S)\text{LastVT}(S) \gtrdot ),即 ) \gtrdot )
  • L,\displaystyle{ L , } 可知 LastVT(L)\text{LastVT}(L) \gtrdot ,,即 i \gtrdot ,) \gtrdot ,
  1. 第二条产生式规则
  • 似乎没有什么推得出来的了
(),i
(\doteq\lessdot\lessdot
)\gtrdot\gtrdot
,\doteq
i\gtrdot

undergraduate/compilers/s05_downtop#3 Martin 算法 ,画图,可以得到下面的结果

public/compile/comxhjfyujkp.svg

LR(1)

有文法 G[S]G[S^\prime]
SSSL=RSRLRLiRL\begin{aligned} S^\prime & \to S \\ S & \to L=R \\ S & \to R \\ L & \to \ast R \\ L & \to i \\ R & \to L \end{aligned}

给出项目集 I0\displaystyle{ I _{ 0 } }I0\displaystyle{ I _{ 0 } } 接受 L\displaystyle{ L } 推导出的 I2\displaystyle{ I _{ 2 } }

解答

public/compile/compile050404fgsdfg.svg

语义 语法

有数组定义
int a[5][10];
int a[5][10];

设数组按行存放,每个 int 占 4 字节,现有语句

while (i < 10)
{
if (i < 5)
{
i = a[i + 1][i * 2];
}
else
{
i = i + 1;
}
}
while (i < 10)
{
if (i < 5)
{
i = a[i + 1][i * 2];
}
else
{
i = i + 1;
}
}

写出该语句翻译成的目标代码(三地址代码或四地址代码)。若目标代码是四元式序列,则请从 100 号单元开始。

解答
Lwb:
if (i < 10) goto Lwy
goto Lwn
Lwy:
if (i < 5) goto Liy
goto Lin
Liy:
T1 := i + 1
T2 := 10 * T1
T3 := i * 2
T4 := T2 + T3
T5 := T4 * 4
T6 := a[T5]
i := T6
goto Linext
Lin:
T7 := i + 1
i := T7
Linext:
goto Lwb
Lwn:
Lwb:
if (i < 10) goto Lwy
goto Lwn
Lwy:
if (i < 5) goto Liy
goto Lin
Liy:
T1 := i + 1
T2 := 10 * T1
T3 := i * 2
T4 := T2 + T3
T5 := T4 * 4
T6 := a[T5]
i := T6
goto Linext
Lin:
T7 := i + 1
i := T7
Linext:
goto Lwb
Lwn:
设有数组定义
int a[5][5];
int a[5][5];

设数组按行存放,每个 int 占 4 字节,现有语句

if (!a)
{
while (i < 10 && j > 0)
{
b = a[i + 1][j * 2];
}
}
b = b * 2;
if (!a)
{
while (i < 10 && j > 0)
{
b = a[i + 1][j * 2];
}
}
b = b * 2;

写出该语句翻译成的目标代码(三地址代码或四地址代码)。若目标代码是四元式序列,则请从 100 号单元开始。

解答
if (a == 0) goto Liy
goto Lin
Liy:
Lwb:
if (i < 10) goto L2
goto Lwnext
L2: if (j > 0) goto Lwy
goto Lwnext
Lwy:
T1 := i + 1
T2 := 5 * T1
T3 := j * 2
T4 := T2 + T3
T5 := T4 * 4
T6 := a[T5]
b := T6
goto Lwb
Lwnext:
Lin:
Tk := b * 2
b := Tk
if (a == 0) goto Liy
goto Lin
Liy:
Lwb:
if (i < 10) goto L2
goto Lwnext
L2: if (j > 0) goto Lwy
goto Lwnext
Lwy:
T1 := i + 1
T2 := 5 * T1
T3 := j * 2
T4 := T2 + T3
T5 := T4 * 4
T6 := a[T5]
b := T6
goto Lwb
Lwnext:
Lin:
Tk := b * 2
b := Tk

翻译

设有文法 G[S]\displaystyle{ G \left[ S \right] }
S(A,(A))A(A)Aε\begin{aligned} S & \to (A, (A)) \\ A & \to (A) \\ A & \to \varepsilon \end{aligned}

给文法配上语义规则,计算并打印出括号嵌套的最大深度。

不知道对不对
S  S{print(S.s)}S  (A,L){S.s=max(A.s,L.s)+1}L  (A){L.s=A.s+1}A  (A1){A.s=A1.s+1}A  ε{A.s=0}\begin{aligned} S ^{\prime} \to \; & S && { \color{blue} \{ \text{print}(S \text{.s}) \} } \\ S \to \; & (A,L) && { \color{blue} \{ S \text{.s}= \max(A \text{.s}, L \text{.s})+1 \} } \\ L \to \; & (A) && { \color{blue} \{ L \text{.s} = A \text{.s} + 1 \} } \\ A \to \; & (A_{1}) && { \color{blue} \{ A \text{.s} = A_1 \text{.s} + 1 \} } \\ A \to \; & \varepsilon && { \color{blue} \{ A \text{.s}=0 \} } \\ \end{aligned}

属性文法

写出 for 循环和 do…while 循环的属性文法

for 循环
Sfor(i=E1Mi<E2Ni++){WS}MεNεWε\begin{aligned} S & \to \text{for(i=}E_1 \text{; } {\color{red}M} \text{i<}E_2 \text{; } {\color{red}N} \text{i++)} \{ {\color{red}W} S \} \\ M & \to \varepsilon \\ N & \to \varepsilon \\ W & \to \varepsilon \\ \end{aligned}
M.label = newLabel
N.label = newLabel
W.label = newLabel
S.code = E1.code
+ gen(`${i} = ${E1.place}`)
+ gen(`${M.label}:`)
+ E2.code
+ gen(`if ${i} < ${E2.place} goto ${W.label}`)
+ gen(`goto ${S.next}`)
+ gen(`${N.label}:`)
+ gen(`${i} = ${i} + 1`)
+ gen(`goto ${M.label}`)
+ gen(`${W.label}:`)
+ S1.code
+ gen(`goto ${N.label}`)
+ gen(`${S.next}:`)
M.label = newLabel
N.label = newLabel
W.label = newLabel
S.code = E1.code
+ gen(`${i} = ${E1.place}`)
+ gen(`${M.label}:`)
+ E2.code
+ gen(`if ${i} < ${E2.place} goto ${W.label}`)
+ gen(`goto ${S.next}`)
+ gen(`${N.label}:`)
+ gen(`${i} = ${i} + 1`)
+ gen(`goto ${M.label}`)
+ gen(`${W.label}:`)
+ S1.code
+ gen(`goto ${N.label}`)
+ gen(`${S.next}:`)
E1.code
i := E1.place
M.label:
E2.code
if (i < E2.place) goto W.label
goto S.next
N.label:
i := i + 1
goto M.label
W.label:
S1.code
goto N.label
S.next:
E1.code
i := E1.place
M.label:
E2.code
if (i < E2.place) goto W.label
goto S.next
N.label:
i := i + 1
goto M.label
W.label:
S1.code
goto N.label
S.next:
do-while 循环
Sdo {MS1} while(NE)W\begin{aligned} S & \to \text{do } \{ {\color{red}M}S_{1} \} \text{ while}({\color{red}N}E) {\color{red}W} \end{aligned}
M.label = newLabel
N.label = newLabel
M.label = newLabel
N.label = newLabel

N 标签用于 continue 语句的跳转

M.label:
S1.code
N.label:
if (E.place) goto M.label
goto W.label
W.label:
M.label:
S1.code
N.label:
if (E.place) goto M.label
goto W.label
W.label:

运行时状态

设 C 语言函数的活动记录结构如下,运行栈自底向上增长
6其他
5临时变量
4局部变量
3老 SP
2返回地址
1形式参数

现有 C 程序如下

int f(int n, int m) {
int k;
if (n + m <= 0)
k = 0;
else
k = n * m + f(n - 1, m - 2);
return k;
}
void main() {
int p;
p = f(5, 4);
// 其他语句
} // 1
int f(int n, int m) {
int k;
if (n + m <= 0)
k = 0;
else
k = n * m + f(n - 1, m - 2);
return k;
}
void main() {
int p;
p = f(5, 4);
// 其他语句
} // 1
  1. 设采用标识符栈来登记标识符的作用域及其他的信息。而且该标识符表的内容需要留到以后阶段使用。当编译到 1 处时,画出标识符栈中的内容。
  2. 运行时当第二次(递归)进入 f 后,即 main() -> f(5, 4) -> f(4, 2) 时,给出整个运行栈的内容。
解答

public/compile/compxtjhgfhu.svg

地址内容从属范围
88kf(4, 2)
89老 BP = 94f(4, 2)
90返回地址f(4, 2)
914f(4, 2)
922f(4, 2)
93kf(5, 4)
94老 BP = 99f(5, 4)
95返回地址f(5, 4)
965f(5, 4)
974f(5, 4)
98pmain
99老 BPmain
100返回地址main