词法分析

比较简单,不多说了。

语法分析

自顶向下分析方法

构造文法的预测分析程序

例题:image-20221025152216009

改写文法,消除左递归

image-20221025152459657

image-20221025152545231

根据改写后的文法,构造状态转换图

image-20221025152657496

化简状态转换图

真的很奇妙,不是吗

image-20221025152805969

同理得

根据化简后的转换图构造程序(注意指针移动)

image-20221025152946737

image-20221025152959418

非递归预测分析

预测分析表的构造
FIRST(X)

定义:X可以推导出的开头终结符号集合

构造方法:

  1. $X$为终结符,则$FIRST(X) = {X}$

  2. $X$为非终结符,且有产生式$X→a…$,其中a为终结符,则$a∈FIRST(X)$

    若有产生式$X→ε$,则$ε∈FIRST(X)$

  3. 若有产生式$X→Y…$,且Y为非终结符,则将$FIRST(Y)$中的所有非$ε$元素加入$FIRST(X)$

    若有产生式$X→Y_1 Y_2…Y_k$,如果对某个$i$,$FIRST(Y_1),FIRST(Y_2),…,FIRST(Y_{i-1})$都含有$ε$,则把$FIRST(Y_i)$中的所有非$ε$元素加入$FIRST(X)$中

    若所有的$FIRST(Y_i)$均含有$ε$,则将$ε$加入$FIRST(X)$

FOLLOW(A)

定义:文法的所有句型中紧跟在A之后出现的终结符号或$组成的集合

构造方法:

  1. 文法开始符号$S$,$∈FOLLOW(S)
  2. 若有产生式$A→αBβ$,则把$FIRST(β)$中的所有非$ε$元素加入$FOLLOW(B)$
  3. 若有产生式$A→αB$,或$A→αBβ$但$ε∈FIRST(β)$,则把$FOLLOW(A)$中的所有元素加入$FOLLOW(B)$
构造预测分析表

image-20221025160706084

如果一个文法的预测分析表不含多重定义的表项,则称该文法为$LL(1)$文法

image-20221025161615499

例:预测分析程序的分析过程

image-20221025161931817

栈中的表达式要倒着写(左边为栈底,右边为栈顶)

匹配时则将栈顶元素出栈,开始匹配输入表达式中下一个符号

错误处理

对非终结符$A$,终结符号$b∈FOLLOW(A)$,如果表项$M[A,b]$为空,则填入$synch$

预测分析程序

image-20221105133927592




自底向上分析方法

LR

分析过程

image-20221025163807497

SLR(1)分析表

image-20221025164100654

构造LR(0)项目集规范族

image-20221025164353150

image-20221025164515132

image-20221025164532265

image-20221025164607645

依次构造从$I_i$出发的有效项目集,直到没有新的有效项目集出现。

构造DFA

image-20221025164806419

构造SLR(1)分析表

LR(0)可能会产生移进-规约冲突或者规约-规约冲突,SLR(1)考察非终结符号的FOLLOW集

image-20221025165235091

LR(1)分析表

书上的概念看不懂,所以直接看例题。

image-20221031102954681

首先还是构造拓广文法(这里已经给出)

构造项目集时要多向后看一位,用逗号隔开写在后面,由某个式子推导出的项目集继承原式子多看一位的符号(?有点啰嗦ww

展望符计算方法:方法

$FIRST(βa)$ ,其中$β$为原式子该非终结符之后的剩余串,$a$为上个状态的展望符

然后构造分析表

image-20221031110110925

image-20221031110224781

LALR(1)分析表
基本思想

①合并LR(1)项目集规范族中的同心集,以减少分析表的状态数

②用项目集的核代替项目集,以减少项目集所需的存储空间

image-20221105091054735

判断文法
$LR(0)$

一个文法是$LR(0)$文法 当且仅当 该文法的每个活前缀的有效项目集中,要么所有的元素都是移进或待约项目,要么只含有唯一的归约项目。

$SLR(1)$ 和 $LR(1)$

image-20221105155437918

移进-规约冲突

image-20221105160716353

规约-规约冲突

image-20221105160730824

image-20221106130946228


语法制导翻译

学艺不精,没学懂……


语义分析

类型检查

类型表达式

数组

$array(I,T)$

元素类型为T,下标集合为I的数组

例:

a:array[1…10] of char;

名字a的类型表达式为array(1…10, char)

笛卡尔乘积

$T_1×T_2$

记录

把类型构造器record作用于记录中各域类型的笛卡尔乘积上就形成了记录的类型表达式,域类型是由域名和域的类型表达式组成的二元组

例:

B : record

​ i : integer;

​ c : char;

​ r : real;

end;

B的类型表达式为record((i×integer)×(c×char)×(r×real))

与此功能相同的C语言的声明语句为:

struct B{

​ int i;

​ char c;

​ float r;

}

指针

如果T是类型表达式,那么pointer(T)也是类型表达式

例:

p: ↑row;

p的类型表达式为pointer(row)

函数

把程序中的函数看成是从定义域类型D到值域R的映射,函数类型由类型表达式$D→R$表示

例:

function fun(a : char, b : integer): ↑integer;

fun的类型表达式为char × integer → pointer(integer)

类型等价

结构等价

如果两个数据类型具有相同的结构,即都是从相同的基本类型出发、用相同的类型构造器由完全相同的方法构造出来的,那它们就是等价的。

名字等价

名字等价把每个类型名看成一个可区别的类型,所以两个类型表达式名字等价,当且仅当它们的名字完全相同。

C语言的类型等价

C语言对struct和union采用名字等价,其他采用结构等价。


运行环境

非局部名字的访问

静态作用域

活动记录、访问链、display表

动态作用域

活动记录的访问链总是指向它的调用者的活动记录

参数传递机制

建议看作业题7.2,结合答案的图看。

传值调用

函数调用不会改变原来参数的值(即函数外的值仍旧保持不变)。

引用调用

传地址。

通过形参访问参数的地址空间,会改变值。

复制恢复

返回时,传入参数为左值,函数内结果为右值(相当于复制结果)。

传名调用

直接把参数名字传进去,牵一发而动全身。

中间代码生成

中间代码形式

后缀表达式、三地址代码、四元式、三元式

后缀表达式

方法一

运算对象顺序相同,运算符紧跟在其运算对象之后

运算符优先级:括号>算术运算符>关系运算符>逻辑运算符

方法二

设置一个运算符号栈,通过进栈出栈的方式

要注意-是减号还是uminus

三地址代码

一般形式:x := y op z

image-20221216203259607

image-20221216203321990

image-20221216203340618

image-20221216203427831

image-20221216203449134

四元式

(op, arg1, arg2, result)

三元式

在四元式基础上,不引入临时变量,用计算中间结果的语句的序号代替临时变量

赋值语句的翻译

image-20221216203857775

数组

一维数组

image-20221216214848716

二维数组

image-20221216214918404

image-20221216214931958

布尔表达式的翻译

运算符优先级:not > and > or

数值表示法

采用数值编码表示逻辑真和逻辑假。

控制流表示法

利用控制到达程序中的位置表示布尔表达式的真值。

image-20221216204652192

回填技术

把转移到某目标的所有待回填语句的标号都存入一个链表。

目标代码生成

代码优化