title: 编译原理 date: 2021-01-07 14:18:25 categories: 学习笔记 tag:
字母表 $\sum$ 是一个<font color=red>有穷的符号集合</font>,符号包括了字母、数字、标点符号……
对于文法 $G$,可以定义为 $G = (V_T, V_N, P, S)$
对于含有相同左部的产生式,可以通过“或”运算简写 例如对于
$$\alpha \rightarrow \beta_1 , \alpha \rightarrow \beta_2 , \dots , \alpha \rightarrow \beta_n$$
可以简写为
$$\alpha \rightarrow \beta_1 | \beta_2 | \dots | \beta_n$$
从语言的规则<font color=red>推导</font>生成语言的过程
根据规则,可以将符号串推成另一个符号串的过程称为推导。用产生式的右部替换产生式的左部
如果是经过多次推导得到,则记为 $a_0 \Rightarrow^n a_n$
$a_0 \Rightarrow^+ a_n$ 表示经过至少一步推导得到 $a_0 \Rightarrow^* a_n$ 表示经过任意步数推导得到
根据语言的规则<font color=red>识别</font>语言的过程
根据规则,可以将符号串还原成。将产生式的右部替换为产生式的左部
$$L(G) = {w | S \Rightarrow^ w, w \in V_T^ }$$
对于 $\forall \alpha \rightarrow \beta \in P$,满足 $\alpha$ 中至少包含一个非终结符
对于 $\forall \alpha \rightarrow \beta \in P$,满足 $|\alpha| \leq |\beta|$
也可以理解为对于 $\forall \alpha A \beta \rightarrow \alpha \gamma \beta \in P$,其中 $\alpha$、$\beta$ 可以为 $\varepsilon$,满足 $\gamma \neq \varepsilon$(在 $A = S$ 的情况下,此等式可以成立)
对于 $\forall \alpha \rightarrow \beta \in P$,满足 $\alpha$ 是一个非终结符
对于 $\forall \alpha \rightarrow \beta \in P$,满足 $\alpha$ 是一个非终结符,而 $\beta$ 只能是空串、一个终结符号或者一个终结符号和一个非终结符号
分析树是推导的图形化表示
如果一个文法可以为某个句子生成多棵分析树,则称这个文法是二义性的
正则表达式(简称:RE)是一种描述正则语言的表示方法,正则表达式可以由较小的正则表达式按照特定规则递归地构建。每个正则表达式 $r$ 定义(表示)一个语言,记为 $L(r)$。这个语言也是根据 $r$ 的子表达式所表示的语言递归定义的
加入 $r$ 和 $s$ 都是 RE,表示的语言分别是 $L(r)$ 和 $L(s)$,则
可以用RE定义的语言叫做正则语言(regular language)或正则集合(regular set)
给一些RE命名,并在之后的RE中像使用字母表中的符号一样使用这些名字
具有一系列离散的输入输出信息和有穷数目的内部状态的系统
对于任意的一个输入,自动机都唯一地确定了下一个状态
定义 $M=(S, \sum, \delta, s_0, F)$ 为一个确定的有穷自动机
确定的有穷自动机可以通过状态图来表示
初始结点通常用 $\Rightarrow$ 表示,终态结点通常为双圈表示
确定的有穷自动机还可以使用表格来表示其状态,例如上述的状态图可以表示为
状态 | 0 | 1 | |
---|---|---|---|
$S_0$ | $S_1$ | $S_0$ | 0 |
$S_1$ | $S_1$ | $S_2$ | 0 |
$S_2$ | $S_1$ | $S_0$ | 1 |
通常,在表格对应行的右端通过01的标注表示这个状态为终态
对于 $\sum^*$ 中的任意符号串 $t$,如果在状态图中存在一条从初态到某一终态的路径,且这条路径上所有弧的标记符连接起来等于 $t$,则称 $t$ 可以被此 DFA 接受
收到一个符号,可能进入不同的状态
定义 $M=(S, \sum, \delta, s_0, F)$ 为一个确定的有穷自动机
NFA 也可以通过状态图来表示和表格进行表示,与 DFA 的状态图类似
参考下面两张图
步骤:
以下图为例 画出如下的表格
序号 | 状态 | a | b |
---|---|---|---|
1 | 0 | 0,1 | 1 |
2 | 0,1 | 0,1 | 1 |
3 | 1 | 0 |
将序号代替状态,重新绘图
以上方的图为例,易得状态 1 和状态 2 是等价状态,所以合并得到
序号 | 状态 | a | b |
---|---|---|---|
1 | 0 | 1 | 2 |
2 | 1 | 1 |
最终得到
从分析树的顶部(根节点)向底部(叶节点)方向构造分析树,可以看成是从文法开始符号S推导出词串w的过程
在最左推导中,总是选择每个句型的最左非终结符进行替换,即优先满足表达式左侧
在最右推导中,总是选择每个句型的最右非终结符进行替换,即优先满足表达式右侧
自顶向下的语法分析采用最左推导方式
当出现了类似如下的推导公式时
$$A \rightarrow A \alpha | \beta$$
时,此时可以出现左递归的情况,这会导致无法正确的进行最左推导,因为可以出现下面的情况:
$$A \Rightarrow A \alpha \Rightarrow A \alpha\alpha \Rightarrow A \alpha\alpha\alpha \Rightarrow A \alpha\alpha\alpha\alpha \dots$$
此时可以将上述的推导公式转换为
$$ \begin{cases} A \rightarrow \beta A' \ A' \rightarrow \alpha A' | \varepsilon \end{cases} $$
将左递归的公式转换为右递归即可
这样的操作的代价是
例如
$$ \begin{cases} S \rightarrow Aa | b \ A \rightarrow Sd | \varepsilon \end{cases} $$
此时可以产生这样的推导
$$S \rightarrow Aa \rightarrow Sda \rightarrow Aada \rightarrow Sdada \dots$$
这时,应该将改为先进行替换得到
$$A \rightarrow Aad | bd | \varepsilon$$
$$ \begin{cases} A \rightarrow bdA' | A' \ A' \rightarrow abA' | \varepsilon \end{cases} $$
当出现
$$S \rightarrow aAd | aBe$$
之类的结构,当读入的第一个字符为 $a$ 时,无法确定应该选择哪个产生式的时候,应该进行左公因子提取,即改编为
$$ \begin{cases} S \rightarrow aS' \ S' \rightarrow Ad|Be \end{cases} $$
$FIRST(A)$ 集表示非终结符 $A$ 能够推导出的所有等式的第一个终结符的集合
$$FIRST(\alpha) = { a | \alpha \Rightarrow a \beta, a \in V_T , \alpha, \beta \in V^* }$$
这条等式可以用下面三个原则来求算
对于一个产生式 $A \rightarrow B$而言
$FOLLOW(A)$ 集表示非终结符 $A$ 后可以跟随哪些终结符
$$FOLLOW(A) = { a | S \Rightarrow^ \dots A a \dots,a \in V_T }$$ $$若 A \Rightarrow^ \dots A,则 # \in FOLLOW(A)$$
这两条等式可以用下面三个原则来求算
表示使用某个产生式的选择符号
$$ \begin{cases} SELECT(A \rightarrow \alpha) = (FIRST(\alpha) - {\varepsilon}) \cup FOLLOW(A),\alpha \Rightarrow^ \varepsilon \ SELECT(A \rightarrow \alpha) = FIRST(\alpha),\alpha \not\Rightarrow^ \varepsilon \end{cases} $$
同时满足
$$SELECT(A \rightarrow \alpha) \cap SELECT(A \rightarrow \beta) = \varnothing$$
满足 LL(1) 的文法有下面三个条件:
若文法存在语句
$$A \rightarrow \alpha | \beta$$
则
$$ \begin{cases} FIRST(\alpha) \cap FOLLOW(A) = \varnothing, \beta \Rightarrow^ \varepsilon \ FIRST(\beta) \cap FOLLOW(A) = \varnothing, \alpha \Rightarrow^ \varepsilon \end{cases} $$
$$对于所有的 A \rightarrow \alpha | \beta$$
若满足
$$SELECT(A \rightarrow \alpha) \cap SELECT(A \rightarrow \beta) = \varnothing$$
则为 LL(1)
首先需要根据 $SELECT$ 集来构建一个分析表。通过表的信息实现语法分析
以下面的表达式文法为例
$$ \begin{cases} E \rightarrow E + T | T \ T \rightarrow T * F | F \ F \rightarrow i | (E) \end{cases} $$
首先,消除左递归,易得,前两个式子均为左递归 得到
$$ \begin{cases} E \rightarrow TE' \ E' \rightarrow +TE' | \varepsilon \ T \rightarrow FT' \ T' \rightarrow *FT' | \varepsilon \ F \rightarrow i | (E) \end{cases} $$
得到各个符号的 FIRST 集:
首先根据2、4、5式得到
$$ \begin{cases} FIRST(E') = {+, \varepsilon} \ FIRST(T') = {*, \varepsilon} \ FIRST(F) = {i, (} \end{cases} $$
然后根据 FIRST 集的求出剩下的 FIRST 集
$$ \begin{cases} FIRST(E) = {i, ( } \ FIRST(T) = {i, ( } \end{cases} $$
然后再求出 FOLLOW 集
首先
$$# \in FOLLOW(E)$$
然后根据第一个等式得到
$$FIRST(E') - \varepsilon \subseteq FOLLOW(T) \Rightarrow FOLLOW(T) = {+}$$ $$FOLLOW(E) \subseteq FOLLOW(E') \Rightarrow FOLLOW(E') = {#}$$
然后继续重复做,直到没有 FOLLOW 集发生更新为止,最终得到
$$ \begin{cases} FOLLOW(E) = { #, ) } \ FOLLOW(E') = { #, ) } \ FOLLOW(T) = { #, +, )} \ FOLLOW(T') = { #, +, )} \ FOLLOW(F) = { #, +, ), *} \end{cases} $$
再得到 SELECT 集
$$ \begin{cases} SELECT(E \rightarrow TE') = FIRST(TE') = FIRST(T) = {i, ( } \ SELECT(E' \rightarrow +TE') = FIRST(+TE') = FIRST(+) = {+} \ SELECT(E' \rightarrow \varepsilon) = (FIRST(\varepsilon) - {\varepsilon }) \cup FOLLOW(E') = { #, ) } \ SELECT(T \rightarrow FT') = FIRST(FT') = FIRST(F) = {i, (} \ SELECT(T' \rightarrow FT') = FIRST(FT') = FIRST() = {} \ SELECT(T' \rightarrow \varepsilon) = (FIRST(\varepsilon) - {\varepsilon }) \cup FOLLOW(T') = { #, +, )} \ SELECT(F \rightarrow i) = FIRST(i) = { i } \ SELECT(F \rightarrow (E)) = FIRST((E)) = FIRST(() = { ( } \ \end{cases} $$
此时,判断是否为 LL(1) 文法 $$ \begin{cases} SELECT(E' \rightarrow +TE') \cup SELECT(E' \rightarrow \varepsilon) = \varnothing \ SELECT(T' \rightarrow * FT') \cup SELECT(T' \rightarrow \varepsilon) = \varnothing \ SELECT(F \rightarrow i) \cup SELECT(F \rightarrow (E)) = \varnothing \end{cases} $$
所以是 LL(1)文法
根据 SELECT 得出下表
i | + | * | ( | ) | # | |
---|---|---|---|---|---|---|
E | $\rightarrow TE'$ | $\rightarrow TE'$ | ||||
E' | $\rightarrow +TE'$ | $\rightarrow \varepsilon$ | $\rightarrow \varepsilon$ | |||
T | $\rightarrow FT'$ | $\rightarrow FT'$ | ||||
T' | $\rightarrow \varepsilon$ | $\rightarrow *FT'$ | $\rightarrow \varepsilon$ | $\rightarrow \varepsilon$ | ||
F | $\rightarrow i$ | $\rightarrow (E)$ |
采用三列分析法来分析,使用 #
表示尾部,假设输入的串为 i+i*i
栈 | 剩余输入 | 输出 |
---|---|---|
E# |
i+i*i# |
|
TE'# |
i+i*i# |
匹配了表中的 $\rightarrow TE'$ |
FT'E'# |
i+i*i# |
$\rightarrow FT'$ |
iT'E'# |
i+i*i# |
$\rightarrow i$ |
T'E'# |
+i*i# |
|
E'# |
+i*i# |
$\rightarrow \varepsilon$ |
+TE'# |
+i*i# |
$\rightarrow +TE'$ |
TE'# |
i*i# |
|
FT'E'# |
i*i# |
$\rightarrow FT'$ |
iT'E'# |
i*i# |
$\rightarrow i$ |
T'E' # |
*i# |
|
*FT'E'# |
*i# |
$\rightarrow *FT'$ |
FT'E'# |
i# |
|
iT'E'# |
i# |
$\rightarrow i$ |
T'E'# |
# |
|
E'# |
# |
$\rightarrow \varepsilon$ |
# |
# |
$\rightarrow \varepsilon$ |
匹配成功
略
从分析树的底部(叶节点)向顶部(根节点)方向构造分析树,可以看成是将输入串w归约为文法开始符号S的过程,自底向上的语法分析采用最左归约方式(反向构造最右推导)
<font color=red>由于 SLR(1) 的操作和 LR(0) 分析法相似,且兼容,所以这里直接写 SLR(1) 的操作过程,LR(0) 文法也可以直接用此方法,得到的结果完全相同</font>
以此文法为例
$$ \begin{cases} S \rightarrow L*L | L \ L \rightarrow LB | B \ B \rightarrow 0 | 1 \end{cases} $$
得到
$$ \begin{cases} S \rightarrow L*L \ S \rightarrow L \ L \rightarrow LB \ L \rightarrow B \ B \rightarrow 0 \ B \rightarrow 1 \end{cases} $$
LR分析法不适用于有多个开始符号的产生式,所以应当对上面的产生式进行处理得到
$$ \begin{cases} 0) S' \rightarrow S \ 1) S \rightarrow L*L \ 2) S \rightarrow L \ 3) L \rightarrow LB \ 4) L \rightarrow B \ 5) B \rightarrow 0 \ 6) B \rightarrow 1 \end{cases} $$
每行开头的为编号,后续通过编号来指代产生式
对于一个状态,首先,判断.
后面是否为非终结符号。如果是,那我们就得找所有由此非终结符推出的产生式,并将它们添加进入此状态里。循环做即可。
使用 .
表示当前匹配到的位置
首先建立初状态,将第一个表达式加入初状态 State 0
此状态中有 $S' \rightarrow .S$
检查 .
后是否为非终结符,得到 $S$,由于 $S$ 是非终结符,所以将 $S$ 的产生式加入此状态得到
$$ \begin{cases} S' \rightarrow .S \ S \rightarrow .L*L \ S \rightarrow .L \ \end{cases} $$
再检查新加入的,得到 $L$ 也需要加入此状态
$$ \begin{cases} S' \rightarrow .S \ S \rightarrow .L*L \ S \rightarrow .L \ L \rightarrow .LB \ L \rightarrow .B \ \end{cases} $$
最后发现 $B$ 也是需要加入此状态的得到 State 0 的最终结果
$$ \begin{cases} S' \rightarrow .S \ S \rightarrow .L*L \ S \rightarrow .L \ L \rightarrow .LB \ L \rightarrow .B \ B \rightarrow .0 \ B \rightarrow .1 \end{cases} $$
接下来的每个状态都是从 State 转换过来的,即将小数点向后移动,可以得到不同的状态 根据其状态内的产生式,可以得到 State 0 可以有 $S, L, B, 0, 1$ 这五个转移方式
设定 State 1 是从 State 0 通过 $S$ 转移过来的
所以可以得到,仅
$$S' \rightarrow S.$$
满足,所以 State 1 即只有此产生式,且不可以再转移
注意,State 1 是第一个产生式的最后的结果,所以此状态作为 Accept
状态,简称 acc
设定 State 2 是从 State 0 通过 $L$ 转移过来
所以可以直接得到的有
$$ \begin{cases} S \rightarrow L.*L \ S \rightarrow L. \ L \rightarrow L.B \ \end{cases} $$
对于第三个式子,其满足条件(.
后为非终结符),所以需要把 $B$ 加入此状态
即得到
$$ \begin{cases} S \rightarrow L.*L \ S \rightarrow L. \ L \rightarrow L.B \ B \rightarrow .0 \ B \rightarrow .1 \end{cases} $$
不断重复上述步骤,得到下面的图和结果 $$ State 0 = \begin{cases} S' \rightarrow .S \ S \rightarrow .LL \ S \rightarrow .L \ L \rightarrow .LB \ L \rightarrow .B \ B \rightarrow .0 \ B \rightarrow .1 \end{cases} $$ $$ State 1 = \begin{cases} S' \rightarrow S. \end{cases} $$ $$ State 2 = \begin{cases} S \rightarrow L.L \ S \rightarrow L. \ L \rightarrow L.B \ B \rightarrow .0 \ B \rightarrow .1 \end{cases} $$ $$ State 3 = \begin{cases} L \rightarrow B. \end{cases} $$ $$ State 4 = \begin{cases} B \rightarrow 0. \end{cases} $$ $$ State 5 = \begin{cases} B \rightarrow 1. \end{cases} $$ $$ State 6 = \begin{cases} S \rightarrow L.L \ L \rightarrow .LB \ L \rightarrow .B \ B \rightarrow .0 \ B \rightarrow .1 \end{cases} $$ $$ State 7 = \begin{cases} L \rightarrow LB. \end{cases} $$ $$ State 8 = \begin{cases} S \rightarrow LL. \ L \rightarrow L.B \ B \rightarrow .0 \ B \rightarrow .1 \end{cases} $$
graph LR
A[State 0] -- S --> B[State 1]
A[State 0] -- L --> C[State 2]
A[State 0] -- B --> D[State 3]
A[State 0] -- 0 --> E[State 4]
A[State 0] -- 1 --> F[State 5]
C[State 2] -- * --> G[State 6]
C[State 2] -- B --> H[State 7]
C[State 2] -- 0 --> E[State 4]
C[State 2] -- 1 --> F[State 5]
G[State 6] -- L --> I[State 8]
G[State 6] -- B --> D[State 3]
G[State 6] -- 0 --> E[State 4]
G[State 6] -- 1 --> F[State 5]
I[State 8] -- B --> H[State 7]
I[State 8] -- 0 --> E[State 4]
I[State 8] -- 1 --> F[State 5]
B[State 1] --> Accept([Accept])
Accept通常状态不需要画出
由此图和上面的集合可以画出表格
<table border="0" cellpadding="0" cellspacing="0" width="576" style="border-collapse: collapse;table-layout:fixed;width:432pt"> <colgroup> <col class="x22" width="72" span="8" style="mso-width-source:userset;width:54pt"> </colgroup> <tbody> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r0"> <td rowspan="2" height="38" class="x21" width="72" style="height:28.5pt;width:54pt;">状态</td> <td colspan="4" class="x21" width="288">ACTION</td> <td colspan="3" class="x21" width="216">GOTO</td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r1"> <td class="x22">0</td> <td class="x22">1</td> <td class="x22">*</td> <td class="x22">$</td> <td class="x22">S</td> <td class="x22">L</td> <td class="x22">B</td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r2"> <td height="19" class="x22" style="height:14.25pt;">0</td> <td class="x22">s4</td> <td class="x22">s5</td> <td class="x22"></td> <td class="x22"></td> <td class="x22">1</td> <td class="x22">2</td> <td class="x22">3</td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r3"> <td height="19" class="x22" style="height:14.25pt;">1</td> <td class="x22"></td> <td class="x22"></td> <td class="x22"></td> <td class="x22">acc</td> <td class="x22"></td> <td class="x22"></td> <td class="x22"></td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r4"> <td height="19" class="x22" style="height:14.25pt;">2</td> <td class="x22">s4</td> <td class="x22">s5</td> <td class="x22">s6</td> <td class="x22">r2</td> <td class="x22"></td> <td class="x22"></td> <td class="x22">7</td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r5"> <td height="19" class="x22" style="height:14.25pt;">3</td> <td class="x22">r4</td> <td class="x22">r4</td> <td class="x22">r4</td> <td class="x22">r4</td> <td class="x22"></td> <td class="x22"></td> <td class="x22"></td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r6"> <td height="19" class="x22" style="height:14.25pt;">4</td> <td class="x22">r5</td> <td class="x22">r5</td> <td class="x22">r5</td> <td class="x22">r5</td> <td class="x22"></td> <td class="x22"></td> <td class="x22"></td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r7"> <td height="19" class="x22" style="height:14.25pt;">5</td> <td class="x22">r6</td> <td class="x22">r6</td> <td class="x22">r6</td> <td class="x22">r6</td> <td class="x22"></td> <td class="x22"></td> <td class="x22"></td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r8"> <td height="19" class="x22" style="height:14.25pt;">6</td> <td class="x22">s4</td> <td class="x22">s5</td> <td class="x22"></td> <td class="x22"></td> <td class="x22"></td> <td class="x22">8</td> <td class="x22">3</td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r9"> <td height="19" class="x22" style="height:14.25pt;">7</td> <td class="x22">r3</td> <td class="x22">r3</td> <td class="x22">r3</td> <td class="x22">r3</td> <td class="x22"></td> <td class="x22"></td> <td class="x22"></td> </tr> <tr height="19" style="mso-height-source:userset;height:14.25pt" id="r10"> <td height="19" class="x22" style="height:14.25pt;">8</td> <td class="x22">s4</td> <td class="x22">s5</td> <td class="x22"></td> <td class="x22">r1</td> <td class="x22"></td> <td class="x22"></td> <td class="x22">7</td> </tr> <!--[if supportMisalignedColumns]--> <tr height="0" style="display:none"> <td width="72" style="width:54pt"></td> <td width="72" style="width:54pt"></td> <td width="72" style="width:54pt"></td> <td width="72" style="width:54pt"></td> <td width="72" style="width:54pt"></td> <td width="72" style="width:54pt"></td> <td width="72" style="width:54pt"></td> <td width="72" style="width:54pt"></td> </tr> <!--[endif]--> </tbody> </table>表的构建原则:
$
状态标识匹配结束符(在LL(1)文法中,使用了 #
作为结束符,实际上两种方法均可作为结束符,只需要在题目中注明即可)sn
其中 n
为转移的目标状态3
即可s4
.
在此产生式的最后既有满足条件的,又有不满足条件的时候 $$ \begin{cases} A_1 \rightarrow \alpha_1 . a_1 \beta_1 \ A_2 \rightarrow \alpha_2 . a_2 \beta_2 \ \dots \ B_1 \rightarrow \gamma_1 . \ B_2 \rightarrow \gamma_2 . \ \dots \end{cases} $$ 显然,前面的产生式为不满足条件的产生式,后面的产生式均为满足条件的产生式 若均满足下列条件,则认为可以通过 SLR 分析法处理,否则认为不可解 $$ \begin{cases} \forall FOLLOW(B_i) \cap {a_1, a_2 \dots } = \varnothing \ \forall FOLLOW(B_i) \cap \forall FOLLOW(B_j) = \varnothing \end{cases} $$ 若满足上述条件,则对于
ACTION
列中的每一项 $a$ 若 $a \in {a_1, a_2 \dots }$,则采用sn
的标识方式,即 若 $a \in FOLLOW(B_i)$,则在所在列标注上rn
,其中n
指代第几号产生式,这条产生式为 $B_i \rightarrow \gamma_i$
rn
标注(若只有此条件的状态,则此时可以称文法为 LR(0) 文法)以 State 2 为例,有四个式子不满足条件,仅一个式子满足条件。其中 $S \rightarrow L.$ 为满足条件的式子,剩下四个均不满足条件。所以我们先求出 $S$ 的 $$FOLLOW(S) = {\$}$$,满足等式 $$FOLLOW(S) \cap {, B, 0, 1} = \varnothing$$ 接着遍历所有
ACTION
内的符号,对于 $0$ 而言,其属于 $${, B, 0, 1}$$ 所以,写入s4
对于 $\$$ 而言,其属于 FOLLOW(S),所以写上 $S \rightarrow L$ 这个产生对应的序号,即r2
略
即将上面的那些产生式带入实际的使用中
例如可以通过下面的文法来描述 C
语言的定义一个变量的过程
产生式 | 语义规则 |
---|---|
$S \rightarrow TL$ | L的类型为T |
$T \rightarrow int$ | T为int |
$T \rightarrow double$ | T为double |
$L \rightarrow L, id$ | 创建一个新的 $$L{右}$$,将其类型设置为 $$L{左}$$ 相同的类型。并创建一个变量,其类型为 $$L_{左}$$ 的类型,名字为 $$id$$ |
$L \rightarrow id$ | 创建一个变量,其类型为 $$L_{左}$$ 的类型,名字为 $$id$$ |
改为用属性来描述,则可以得到如下表格
产生式 | 语义规则 |
---|---|
$S \rightarrow TL$ | L.type = T.type |
$T \rightarrow int$ | T.type = int |
$T \rightarrow double$ | T.type = double |
$L \rightarrow L, id$ | L(右).type = L.type <br>CreateVar(type = L.type, name = id.name) |
$L \rightarrow id$ | CreateVar(type = L.type, name = id.name) |
对于一个产生式产生的语义规则中,如果产生式左部的属性是仅通过右部的属性得到的,则称此属性为<font color=red>综合属性</font>。而如果产生式右部的属性是通过右部的属性或者左部的属性得到的,则称为<font color=red>继承属性</font>
仅仅使用综合属性的SDD称为S属性的SDD,或S-属性定义、S-SDD
一个SDD是L-属性定义(L-SDD),当且仅当它的每个属性要么是一个综合属性,要么是满足如下条件的继承属性:假如存在一个产生式 $A \rightarrow X_1 X_2 X_3 \dots$,若存在一个 $X_i$,它的一个属性值与下面的有关
例如上面的图片即为 L-SDD
语法制导翻译方案(SDT)是在产生式右部中嵌入了程序片段(称为语义动作)的CFG(上下文无关文法)
例如
$$ \begin{cases} D \rightarrow T {L.type = T.type } L \ T \rightarrow int {T.type = int } \ T \rightarrow double {T.type = double } \ L \rightarrow { L_1.type = L.type } L_1, id \end{cases} $$
嵌入规则如下
使用时,当在进行规约操作时,需要同时执行此程序片段
x = b * (c + d) + a
(+, c, d, t1)
(*, b, t1, t2)
(+, t2, a, t3)
(=, t3, , x)
(a > b) && (c < d) || (e < f) && (!g)
(j>, a, b, 3)
(j, , ,5)
(j<, c, d, true)
(j, , , 5)
(j<, e, f, 7)
(j, , , false)
(jnz, g, , true)
(j, , , false)
if (a > 0) x = x + 1 else x = 4 * (x - 1)
(j>, a, 0, 3)
(j, , , 6)
(+, x, 1, t1)
(=, t1, , x)
(j, , , 9)
(-, x, 1, t2)
(*, 4, t2, t3)
(=, t3, , x)
9.为每个静态过程都逐段分配存储空间,每个过程的内存空间都相互独立且不相交
优点:处理上简单 缺点:对内存空间的使用不够经济合理
通过对过程间的调用关系进行分析,凡属无相互调用关系的并列过程,尽量使其局部数据<font color=red>共享</font>存储空间
将内存认为是一个栈空间
当一个过程被调用时,向栈中推入一个活动记录,当此过程结束时,该记录被弹出栈
用来描述程序运行期间控制进入和离开各个活动的情况的树称为活动树。在表示过程 p 的某个活动的结点上,其子结点对应于被 p的这次活动调用的各个过程的活动。按照这些活动被调用的顺序,自左向右地显示它们。一个子结点必须在其右兄弟结点的活动开始之前结束
暂略
暂略
暂略
暂略
划分方法:
例如对于代码
i = m - 1;
j = n;
v = a[n];
while (1) {
do i = i + 1; while(a[i] < v);
do j = j - 1; while(a[j] > v);
if (i >= j) break;
x = a[i];
a[i] = a[j];
a[j] = x;
}
x = a[i];
a[i] = a[n];
a[n] = x;
可以划分出 6 个基本块
B1:
i = m - 1;
j = n;
v = a[n];
B2:
i = i + 1;
if a[i] < v goto B2
B3:
j = j - 1;
if a[j] > v goto B3
B4:
if i >= j goto B6
B5:
x = a[i];
a[i] = a[j];
a[j] = x;
goto B2
B6:
x = a[i];
a[i] = a[n];
a[n] = x;
根据上面的基本块,再根据其转跳关系,可以绘制流图
graph LR
B1 --> B2
B2 --> B2
B2 --> B3
B3 --> B3
B3 --> B4
B4 --> B5
B4 --> B6
B5 --> B2
暂略
将基本块通过 DAG(有向无环图) 表示
例如对于代码
a = b + c;
b = b - d;
c = c + d;
e = b + c;
可以绘制出如下的 DAG 图(通常在图上标注运算符号而不是字母,这里为了更容易理解标注了字母)
graph LR
b0((b)) --> a0((a))
c0((c)) --> a0((a))
b0((b)) --> b1((b))
d0((d)) --> b1((b))
c0((c)) --> c1((c))
d0((d)) --> c1((c))
c1((c)) --> e0((e))
b1((b)) --> e0((e))
若结果 e
是需要返回的值,即其他基本块需要使用的值,则通过 DAG 图可知,变量 a
是无用的,可以删除
得到新的图为
graph LR
b0((b)) --> b1((b))
d0((d)) --> b1((b))
c0((c)) --> c1((c))
d0((d)) --> c1((c))
c1((c)) --> e0((e))
b1((b)) --> e0((e))
所以可以得到优化后的代码为
b = b - d;
c = c + d;
e = b + c;
略
暂略