编译阶段

给出可能出错的代码,或者出错的方式,询问是在编译的哪个阶段会发生报错

比如:

1
2
3
4
5
// c代码
int t=0,2ddd; // 1. 变量名命名错误
t = 1+; // 2. 运算符使用错误
int a[3];
a[3] = 10;// 3. 数组越界
  1. 在词法分析阶段报错
  2. 在语法分析阶段报错
  3. 在语义分析阶段报错(其还包括调用未定义的函数)

词法分析

状态转换图的接收与拒绝

比如下图:

image-20220529181742402

图中一开始有箭头(出发端没有元素)指向的状态为初态(图中A),有两层圈的状态为终态(图中E,F)。

对于任意一个输入串,比如011,其满足从初态出发,在经过对应字符的遍历A->D->C->F后,到达终态(即最后一个点为终态)则可以接收这个输入串,反之(最后一个点不是终态)则不可以接收

状态转化矩阵

比如:

状态 a(对应第一列状态的情况下输入a) b(对应第一列状态的情况下输入b)
S A S
A A B
B B B

初态:S,终态:B

矩阵表示的当处于S状态时,当接收a时,下一个状态为A,当接收b时,下一个状态S。其他同理,根据合格规则可以绘制出状态转换图。初态和终态在给出状态转化矩阵时,一般都会直接给出。

正规式(正则表达式)运算符的优先级

a,表示闭包,即当前字符a可以出现0次或多次(优先级最高)ab,表示连接,ab字符连接起来,正常情况下可以写成ab(优先级次之)ab,表示选择,即该字符从ab中选择一个(优先级最低)a*,表示闭包,即当前字符a可以出现0次或多次(优先级最高)\\ a\cdot b,表示连接,即a与b字符连接起来,正常情况下可以写成ab(优先级次之)\\ a | b,表示选择,即该字符从a和b中选择一个(优先级最低)

NFA的确定化

比如下图:

image-20220529182951037

这种题型包括两种类型,一种是带ϵ\epsilon和不带ϵ\epsilon的。

两者区别就在于如果是带ϵ\epsilon的类型就需要先计算每个状态的ϵclosure\epsilon-closure(空闭包),不带ϵ\epsilon可以跳过(因为不带ϵ\epsilonϵclosure\epsilon-closure就是状态自己本身)

这题首先要计算ϵclosure\epsilon-closure

状态 ϵclosure\epsilon-closure
{S} {S}
{R} {R,U}
{X} {X}
{Y} {Y}
{U} {U}
{Z} {Z}

并且可以确定初态为S,终态为Z

然后使用S初态的空闭包作为DFA最初的元素,然后根据输入的不同符号,确定其可以到达的下一个状态集合,并对状态集合中的每一个元素的空闭包求一个并集,作为最终状态。如果产生了新的状态,就根据这个新的状态,按照输入的符号判断下一个状态,如果又产生了新的状态就重复之前的操作,直至没有新的状态产生。于是可以得到状态转换矩阵(其中我用Q对新状态进行重命名)

举个例子:
S输入b后可以到达的下一个状态为{R,U},对这两个状态的空闭包取一个并集,即{R,U}并{U} = {R,U},这个就是S输入b后在DFA中最终到达的状态

状态 a b
Q1 = {S} {Z}=Q2 {R,U}=Q3
Q2 = {Z} \empty \empty
Q3 = {R,U} {X,S}=Q4 {Z}=Q2
Q4={X,S} {Z}=Q2 {Y,U,R}=Q5
Q5={Y,U,R} {U,S,X}=Q6 {Z}=Q2
Q6={U,S,X} {S,Z} = Q7 {Z,R,U,Y}=Q8
Q7={S,Z} {Z}=Q2 {R,U}=Q3
Q8={Z,R,U,Y} {X,S,U}=Q6 {Z}=Q2

这是DFA的状态转化矩阵,然后是要确定初态和终态,首先初态就是NFA中的初态的空闭包元素(Q1),而在NFA中的终态是Z,那么在DFA中包含Z的状态都是终态(Q2,Q7,Q8)

(ps,图我就不画了,反正按着上面的矩阵画就不会错了,考试的时候一定要画图)

DFA最小化

如下图:

image-20220529200134790

首先将图中的状态集合按照是否为终态划分成两部分,称为π0=[{0,1},{2,3,4,5}]\pi_{0}=[\{0,1\},\{2,3,4,5\}],然后检查每个被拆分的集合中,是否还有可分的元素。解决过程如下

因为{0,1}a={1}{0,1},{0,1}b={2,4}{2,3,4,5}\{0,1\}_a=\{1\} \in \{0,1\},\{0,1\}_b=\{2,4\}\in \{2,3,4,5\}不可区分,所以先不处理{0,1}\{0,1\}
因为{2,4}a={1,0}{0,1},{3,5}a={3,5}{2,3,4,5}\{2,4\}_a = \{1,0\} \in \{0,1\},\{3,5\}_a=\{3,5\} \in \{2,3,4,5\}可以区分,所以{2,3,4,5}\{2,3,4,5\}被拆分为{2,4},π4={3,5}\{2,4\},\pi_4=\{3,5\}
于是生成新的状态集合π1=[{0,1},{2,4},{3,5}]\pi_1 = [\{0,1\},\{2,4\},\{3,5\}]
因为{2,4}a={1,0}{1,0},{2,4}b={3,5}{3,5}\{2,4\}_a = \{1,0\} \in \{1,0\},\{2,4\}_b=\{3,5\}\in\{3,5\},不可区分,所以不处理{2,4}\{2,4\}
因为{3,5}a={3,5}{3,5},{3,5}b={2,4}{2,4}\{3,5\}_a=\{3,5\}\in\{3,5\},\{3,5\}_b=\{2,4\}\in\{2,4\},不可区分,所以不处理{3,5}\{3,5\}
最后的结果为:π=[{0,1},{2,4},{3,5}]\pi=[\{0,1\},\{2,4\},\{3,5\}]
然后将对应的状态进行合并就行,结果如下图
image-20220529201819585

正规式与NFA的互相转化

转化规则为:

image-20220529202347407

在转化成NFA时,优先做优先级低的操作,即选择->链接->闭包

NFA转成正则式,也用相同的规则就行了

比如将正规式0(01)010^*|(0|1)01^*构造成NFA过程如下:

image-20220529203220838

语法分析

文法的分析树,最左推导,最右推导(规范推导)

文法树:按着文法以树的方式展开成对应的句子

最左推导:优先满足最左端符号的匹配,按照文法展开成对应的句子

最右推导:优先满足最右端符号的匹配,按照文法展开成对应的句子。

image-20220529205141046

文法二义性

证明一个文法存在二义性,只需要找到一个句子,他有两棵不同的语法树(或者两种不同的最左,最右推导)。

已知文法G[S]:S->SaS|SbS|cSd|eS|f,证明该文法是二义的:
(ps:我这里写了两种方式,但其实只用写出推导或者语法树就可以了)
image-20220529220455306

FIRST集与FOLLOW集

FIRST集和FOLLOW集,针对的都是非终结符

假设要求S的FIRST集,首先需要看一下所有左边是S的推导式,然后找出右边第一个符号,如果是非终结符,那么他就是FIRST集的元素之一,如果他是非终结符,那么还要按照相同的方法,先找出这个非终结符的FIRST集,然后将FIRST集作为S的FIRST集元素(和本身自己的取并集),如果非终结符可以得到ϵ\epsilon,那么还要跳过这个非终结符往后看一下是终结符还是非终结符,然后同上操作,FIRST是带ϵ\epsilon不带$\$

假设要求S的FOLLOW集,先给文法起始点的follow集添加一个$\$符,然后要找出所有推导式右边存在S的推导式,然后看S的右边一个元素是什么,如果是终结符,他就是S的FOLLOW集之一,如果是非终结符则这个非终结符的FIRST集中非空的部分也是S的FOLLOW集之一,如果这个非终结符可以表示ϵ\epsilon则再向后看一个符号,同上操作。如果S的后面没有符号了,那么这个推导式左边元素的FOLLOW集也是S的FOLLOW集之一。FOLLOW集是带$\$不带ϵ\epsilon

LL(1)文法

判断是否为LL(1)文法的方法:

  1. 不存在左递归
  2. 对于所有的非终结符,其可以选择的所有转化方式的FIRST集(如果可以转化为ϵ\epsilon,则使用非终结符的FOLLOW集)相交的结果为\empty

举个例子:

已给文法 S->SaB S->bB A->S A->a B->Ac

  1. 这个文法是不是LL(1)文法,如果是请构造LL(1)文法分析表,如果不是,请将其改造成LL(1)文法,然后写出文法分析表
  2. 并给出句子bac的分析过程
  1. 不是LL(1)文法,因为该文法存在左递归,消除左递归后的文法为:

    SbBSSaBSϵASAaBAcS\rightarrow bBS' \\ S'\rightarrow aBS'|\epsilon\\ A\rightarrow S\\ A \rightarrow a \\ B \rightarrow Ac

  2. 然后计算这些推导式的FIRST和FOLLOW集

  3. 对于FIRST(S)FIRST(S),在S在左边的所有推导式中,右边第一个字符的集合为{b}\{b\},所以FIRST(S)={b}FIRST(S) = \{b\}

    对于FIRST(S)FIRST(S'),在SS'在左边的所有推导式中,右边第一个字符的集合为{a,ϵ}\{a,\epsilon\},所以FIRST(S)={a,ϵ}FIRST(S')=\{a,\epsilon\}

    对于FIRST(A)FIRST(A),在AA在左边的所有推导式中,右边第一个字符分别为S,和a,那么a一定是FIRST(A)FIRST(A)的一个元素,对于非终结符S,其FIRST集也是FIRST(A)FIRST(A)的元素,所以FIRST(A)={a}FIRST(S)={a,b}FIRST(A)=\{a\}\bigcup FIRST(S) =\{a,b\}

    对于FIRST(B)FIRST(B),在B在左边的所有推导式中,右边第一个字符为A,那么FIRST(A)FIRST(A)中的元素,一定是FIRST(B)FIRST(B)中的元素,所以FIRST(A)=FIRST(B)={a,b}FIRST(A)=FIRST(B)=\{a,b\}

  4. 首先给初始的推导式添加一个$\$符号,即FOLLOW(S)={$}FOLLOW(S)=\{\$\},然后在S在右边的所有推导式中ASA\rightarrow S\\,S的右边是空的,那么可以得到FOLLOW(S)={$}FOLLOW(A)FOLLOW(S) = \{\$\} \bigcup FOLLOW(A)

    然后计算FOLLOW(A)FOLLOW(A),在A在右边的所有推导式中BAcB\rightarrow Ac,A的右边一个元素是c,那么c就是FOLLOW(A)FOLLOW(A)的元素之一,然后后面没有A在右边的推导式了,所以FOLLOW(A)={c}FOLLOW(A)=\{c\},所以FOLLOW(S)={$}FOLLOW(A)={$,c}FOLLOW(S) = \{\$\} \bigcup FOLLOW(A)=\{\$,c\}

    然后计算FOLLOW(S)FOLLOW(S'),在SS'在右边的所有推导式中SbBSSaBSS\rightarrow bBS',S'\rightarrow aBS',对于第一项,因为SS'的右边为空,所以FOLLOW(S)FOLLOW(S)SS'的元素之一,在第二项中,SS'的右边也为空,所以FOLLOW(S)FOLLOW(S')也是元素之一,所以FOLLOW(S)=FOLLOW(S)FOLLOW(S)={$,c}FOLLOW(S') = FOLLOW(S)\bigcup FOLLOW(S') = \{\$,c\}

    最后计算FOLLOW(B)FOLLOW(B),在B在右边的所有推导式中SbBSSaBSS\rightarrow bBS',S'\rightarrow aBS',B的右边为SS',所以FIRST(S)FIRST(S')应该为FOLLOW(B)FOLLOW(B)的元素,然后由于有SϵS'\rightarrow \epsilon,所以会有新的产生式SbBS\rightarrow bB,此时B的右边是空,所以FOLLOW(S)FOLLOW(S)应该也是FOLLOW(B)FOLLOW(B)的元素,所以FOLLOW(B)=FIRST(S)FOLLOW(S)={a,c,$}FOLLOW(B) = FIRST(S')\bigcup FOLLOW(S) = \{a,c,\$\}

  5. 为了方便查看,画一个表吧

    非终结符 FIRST FOLLOW
    S b $,c\$,c
    SS' a,ϵa,\epsilon $,c\$,c
    A a,b c
    B a,b $,a,c\$,a,c
  6. 然后需要验证这个改造后的文法是不是LL(1)文法,首先对所有有不同推导结果的非终结符S,AS',A,每个终结符在自己可选择的内容中的FIRST的交集(如果是ϵ\epsilon求变换成这个非终结符的FOLLOW集)必须为空,即

    对于S’:FIRST(aBS)FOLLOW(S)={a}{$,c}=对于AFIRST(S)FIRST(a)={b}{a}=对于S’:FIRST(aBS')\bigcap FOLLOW(S’) = \{a\}\bigcap \{\$,c\} = \empty\\ 对于A:FIRST(S)\bigcap FIRST(a) = \{b\} \bigcap \{a\} = \empty

    因为交集都是空,所以这个文法是LL(1)文法

  7. 写出文法分析表,文法分析表从左边的终结符出发,然后看看他的FIRST集有哪些,然后FIRST集中的元素可以对应到终结符的推导式中,将其填入表中,如果是ϵ\epsilon则要看他的FOLLOW集,FOLLOW集对应的非终结符和终结符对应的格子,就是填终结符转化成ϵ\epsilon的格子,如下表

    非终结符 a b c $\$
    S SbBSS\rightarrow bBS'
    SS' SaBSS'\rightarrow aBS' SϵS'\rightarrow \epsilon SϵS'\rightarrow \epsilon
    A AaA\rightarrow a ASA\rightarrow S
    B BAcB\rightarrow Ac BAcB\rightarrow Ac
  8. 最后就是对给定的句子进行分析,首先把初态放入分析栈中,句子放入输入缓冲区并添加一个$\$,然后根据输入缓冲区碰到的最左边的元素决定使用哪条产生式,然后将分析栈中的元素出栈,将产生式右边的部分按从y右到左的方式入栈,然后继续匹配,如果匹配成功,就直接将缓冲区和栈中的字符弄出去。直到分析栈和输入缓冲区都只剩下$\$,如果按照分析表遇到空的情况则分析失败。题目分析结果如下表

    步骤 分析栈 输入缓冲区 输出产生式
    1 $S\$S bac$bac\$ SbBSS\rightarrow bBS'
    2 $SBb\$S'Bb bac$bac\$ 匹配b
    3 $SB\$S'B ac$ac\$ BAcB\rightarrow Ac
    4 $ScA\$S'cA ac$ac\$ AaA\rightarrow a
    5 $Sca\$S'ca ac$ac\$ 匹配a
    6 $Sc\$S'c c$c\$ 匹配c
    7 $S\$S' $\$ SϵS'\rightarrow \epsilon
    8 $\$ $\$ 匹配成功

LR(0)文法

判断是否是LR(0)文法的方法:查看所生成的识别活前缀的DFA中,是否存在移进规约冲突(即一个状态既存在移进又存在规约)。

注意:LR系列的文法都不需要消除左递归,只有LL需要消除左递归

举个例子:

设已给文法G[S]:S->aSb,S->aSc,S->ab

  1. 构造他的识别全部活前缀的DFA
  2. 构造LR(0)分析表
  3. 给出LR(0)分析表对输入符号串aaabcb的分析过程
  1. 首先需要对文法进行拓展,需要添加一条SSS'\rightarrow S,结果如下:

    (0):SS(1):SaSb(2):SaSc(3):Sab(0): S'\rightarrow S\\ (1): S\rightarrow aSb\\ (2): S\rightarrow aSc\\ (3): S\rightarrow ab\\

  2. 然后开始构造识别活前缀,首先取出0的产生式,然后在其右部的最左边写上一个\cdot的标记,然后查看这个标记的右边是否是非终结符,如果是的话这个状态就结束了,不然就需要将左部是这个非终结符的产生式全部写入状态中,然后在产生式右边的最左边写上标记\cdot,直至不再有新的非终结符出现,然后根据记号右边的一个元素,对这个状态进行输入,然后产生的新的状态的这个产生式的记号,向右移动一个字符,按照之前的方法构建这个状态。然后按照相同的方法生成新的状态,直至不再产生新的状态(标记移动到产生式右部的最右边就不会再移动了)。题目的结果如下图所示:

    image-20220530104131101

  3. 然后根据这个DFA构造LR(0)分析表,分析表分为两个部分,action(终结符输入),goto(非终结符输入)。从0状态出发,观察0状态可以接收的输入符号,然后跳转到对应的下一个状态中,或者使用生成式进行规约(规约就用对应的产生式填完一行的ACTION部分就行)。当拓展出的产生式标记到达最右边时,说明这个输入串可以被接收。分析表构建如下

    状态 ACTION GOTO
    a b c $\$ S
    0 S2S_2 1
    1 acc
    2 S2S_2 S4S_4 3
    3 S5S_5 S6S_6
    4 r3r_3 r3r_3 r3r_3 r3r_3
    5 r1r_1 r1r_1 r1r_1 r1r_1
    6 r2r_2 r2r_2 r2r_2 r2r_2
  4. 分析符号串aaabcb,把$\$和初始状态放入到分析栈中,句子带上$\$,放入余留输入串中,然后根据栈顶状态和余留输入串的第一个字符,判断移进和规约操作,并确定下一个状态,如果是移进将字符和状态分别放入分析栈中,然后进行下一轮分析。如果是规约的话,就按照产生式,将右部有的符号全部出栈,然后根据剩下的栈顶状态,配合产生式左部的非终结符判断下一个状态应该goto到哪个状态。如果碰到表格中空白的地方,就直接分析失败,如果碰到了ACC就是分析成功,分析过程如下表

    步骤 分析栈 余留输入串 分析动作 下一状态
    1 $0\$0 aaabcb$aaabcb\$ 移进S2S_2 2
    2 $0a2\$0a2 aabcb$aabcb\$ 移进S2S_2 2
    3 $0a2a2\$0a2a2 abcb$abcb\$ 移进S2S_2 2
    4 $0a2a2a2\$0a2a2a2 bcb$bcb\$ 移进S4S_4 4
    5 $0a2a2a2b4\$0a2a2a2b4 cb$cb\$ 规约r3r_3 GOTO(2,S)=3
    6 $0a2a2S3\$0a2a2S3 cb$cb\$ 移进S6S_6 6
    7 $0a2a2S3c6\$0a2a2S3c6 b$b\$ 规约r2r_2 GOTO(2,S) = 3
    8 $0a2S3\$0a2S3 b$b\$ 移进S5S_5 5
    9 $0a2S3b5\$0a2S3b5 $\$ 规约r1r_1 GOTO(0,S)=1
    10 $0S1\$0S1 $\$ 分析成功

SLR(1)文法

这个文法尝试使用FOLLOW集的方式解决移进规约冲突的问题,即如果一个状态出现了规约和移进,那么规约后生成的非终结符的FOLLOW集与移进接收的符号没有交集,则可以解决冲突,这个解决冲突的方案就是SLR(1),就是解决冲突的地方不一样,其他和LR(0)基本一致。

举个例子:

已知文法G[S]:

(1):S->Pa (2): S->Pb (3):S->C (4): P->Pd (5): P->Se (6)P->f

判断文法G[S]分别是LR(0)和SLR(1)文法吗?为什么?若G[S]是LR(0)文法,请构造其相应的LR(0)的分析表,若G[S]是SLR(1)文法,请构造其相应的SLR(1)的分析表

  1. 首先要添加一个拓展文法(0): S’ ->S

  2. 然后尝试画出他的识别活前缀DFA(过程和LR(0)一致),结果如下图所示:

  3. image-20220530112408647

  4. 从图中可以看出,I1状态存在移进规约冲突所以不是LR(0)文法,然后按照之前说的,看看移进所需的字符{e}\{e\}和FOLLOW(S’)是否有交集(FOLLOW集的求解我就不具体写了,详细可以去之前的内容看看),那么{e}FOLLOW(S)={e}{$}=\{e\}\bigcap FOLLOW(S') = \{e\}\bigcap\{\$\}=\empty,所以冲突可以被解决,这是一个SLR(1)文法

    状态 FOLLOW
    SS' $\$
    S $,e\$,e
    P a,b,d
  5. 然后绘制SLR(1)分析表,绘制过程对于移进的地方基本一致,但是规约的地方不一样了,对某个非终结符的规约,会选择这个非终结符和这个非终结符对应的FOLLOW集指向的格子填写规约。结果如下表

    状态 ACTION GOTO
    a b c d e f $\$ S P
    0 S3S_3 S4S_4 1 2
    1 S5S_5 acc
    2 S6S_6 S7S_7 S8S_8
    3 r3r_3 r3r_3
    4 r6r_6 r6r_6 r6r_6
    5 r5r_5 r5r_5 r5r_5
    6 r1r_1 r1r_1
    7 r2r_2 r2r_2
    8 r4r_4 r4r_4 r4r_4

    (如果还有分析句子的话,分析过程按照表来然后过程和LR(0)完全一致)

LR(1)文法

LR(1)文法是在SLR(1)上的进一步拓展,如果使用FOLLOW集无法解决移进规约规冲突,则可以在生成活前缀中尝试引入第二分量,对于一开始引入的拓展文法,他的第二分量就是$\$,然后如果有新的非终结符引入新的产生式,那么他的第二分量就根据其来源的地方的右边字符,如果字符是终结符就直接作为第二分量,否则则是非终结符的first集,如果非终结符可以为空还要再分析一下

举个例子:

已知文法G[Z]:

(1)Z->Aa (2)Z->bAc (3)Z->dc (4) Z->bda (5) A->d

判断文法G[Z]是SLR(1)文法吗?为什么?若不是SLR(1)文法,可以用什么分析法对文法G[Z]产生的语言进行有效的分析,并给出其分析表

  1. 不是SLR(1)文法,因为项目集{Ad,Zdc}\{A\rightarrow d\cdot, Z\rightarrow d\cdot c\}存在移进规约冲突,且FOLLOW(A)={a,c}FOLLOW(A)=\{a,c\}{c}\{c\}的交集为{c}\{c\},因此文法G[Z]不是SLR(1)文法,对文法G[Z]产生的语言可以使用LR(1)分析法进行有效分析。(ps:这里的项目及主要就是使用之前的构造方式构造了DFA然后找出冲突项然后分析,这里就不详细展开了)

  2. LR(1)文法,仍然要先进行拓广文法:(0)Z’->Z,并获得识别活前缀的DFA(带有第二分量),如下

    image-20220530145254902

  3. 构造分析表的时候,正常写就是按照接收的字符串来,只有在规约的时候与SLR(1)有点不一样,在规约的时候,是根据第二分量的符号来确定是否进行规约,分析表如下表

    状态 ACTION GOTO
    a b c d $\$ Z A
    0 S3S_3 S4S_4 1 2
    1 acc
    2 S5S_5
    3 S6S_6 7
    4 r5r_5 S10S_{10}
    5 r1r_1
    6 S9S_9 r5r_5
    7 S8S_8
    8 r2r_2
    9 r4r_4
    10 r3r_3
  4. 分析句子也是和之前的方式一样

中间代码生成

语法制导翻译

两种类型,一个是已知翻译方式,求句子翻译的输出结果,另一个是已知句子翻译的输出结果,找到文法的翻译方式。

举个例子:

文法G[S]及相应的翻译方案如下:

S->bAb {print:“1”}

A->cB {print:“2”}

A->a {print:“3”}

B->Aad {print:“4”}

输入串为bcaadb时,该翻译方案的输出是什么?

首先画出这个句子的语法树,然后按照最左规约的方式在句子进行规约的顺序进行标号,当完成规约后直接输出规约方式对应的翻译内容即可。

image-20220530151647513

举个例子:

已知文法G[D]:

D-> int id | real id | D1, id

请你将其翻译,使其能够统计一共说明了多少个变量

image-20220530152348098

算术表达式转化

  1. 转化成语法树的形式
  2. 转化成有向无环图DAG的形式
  3. 转化成后缀表达式(逆波兰式)
  4. 三地址代码

举个例子:

把算数表达式(a+b)×(b+c)-(a+b)\times(b+c)翻译成语法树,有向无环图DAG,后缀表达式,三地址代码

image-20220530152754418

三地址代码转化

需要根据下面的控制流语句的翻译图进行(if-then-else语句中如果then的部分被嵌套在while里,他除了回到while的判断状态,还要goto到if结束的状态,不要问为什么,问就是和课本保持一致,反正图中的深蓝色的部分要特别注意)

image-20220530160638996

举个例子:

请将下面的语句翻译成三地址代码:

if (z<x) or (z>y) then

​ while(x>y) do a = a+1;

else a = a-1;

x = y+z;

先把代码换成更直观的转化图(稿纸上做),然后开始翻译三地址代码,注意红框的部分,就是为了和教材翻译过程一致(if的then后面要加一个goto表明他结束后要去哪里),虽然并没有什么用,但是一定要加(至少我学校是这样的)。

image-20220530162527735

不太懂的东西

image-20220530163018720