编译原理第七章 中间代码生成(1)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
通常用于表达式的中间表示
中缀 (运算符在操作数的中间) a*b 前缀式(运算符在操作数的前面) *ab 后缀式(运算符在操作数的后面) ab*
由抽象语法树生成后缀式
中缀式: a*d + b*c + e
+ + * a d b * e 后根遍历生成后缀式:
ad*bc*+e+
先根遍历生成前缀式:
中间代码生成在编译器中的作用
词法分析 目标代码生成
语法分析
中间代码优化
语义分析
中间代码生成
分析
合成
中间代码生成
中间代码生成是将源程序翻译成中间表示的 过程 目的:增强语言的可移植性、进行优化; 中间代码生成方法:
语法制导的翻译方法:属性文法和动作文法 基于Token序列
基于抽象语法树
由Token序列生成后缀式(2)
带括号表达式的后缀式例子
中缀式: (a + (d + b) * c ) + e #
后缀式: a d b + c * +e +
Operator stack 运算符栈 S1
Operand stack
运算源自文库量栈 S2
7.1 常见的中间表示
抽象语法树-AST 无环有向图-DAG(共享的AST)
中间代码生成
M1
源程序
词 法 Token 分 析 序列 器
语 法 语法 分 分析 析 树 器
语 义 分 析 器
中 间 代 中间代码 码 生 成 器
…
Mn
7.1 常见的中间表示
后缀式,逆波兰式 抽象语法树 无环有向图 三元式
四元式
三地址中间代码
7.1 常见的中间表示
后缀式(逆波兰式)
+ +
a*c + a*c + e
e
+ +
e
* a
c a AST
* c a
* c
* a
DAG c
7.1 常见的中间表示
三地址中间代码
三地址:两个操作分量和一个结果的抽象地址; 为方便起见, 通常用变量名代替抽象地址; 三元式 No. (op, operand1, operand2) 编号 (操作符, 操作分量1, 操作分量2) 其中操作分量可以是变量名(抽象地址)或者编号 四元式 (op, operand1, operand2, result) (操作符, 操作分量1, 操作分量2, 结果) 其中操作分量可以是变量名(抽象地址)或者临时变量 (抽象地址)
实在函数/过程: (funKind, actual, label) 形参函数/过程: (funKind, formal, level, offset)
c
++*ad*bce
抽象语法树
由Token序列生成后缀式(1)
(1)初始化: S1和S2为空; (2) 读token: tk=ReadOne(); (3) Switch tk of (i) #: if (S1为空) exit; else while (S1不为空) /*产生剩余操作符的后缀表示*/ {op = pop(S1); (str1, str2)=pop(2); push(S2, str2 + str1+ “op”);} (ii)运算分量: push(tk, S2); goto (2); (iii)运算符: if (S1为空 || tk优先级大于Top(S1)) { push (tk, S1); goto(2);} else { while(tk小于等于Top(S1) && S1不为空)) { op = pop(S1); (str1, str2)=pop(2); push(S2, str2+str1 + “op”); } push(tk, S1); goto (2); }
三地址代码的例子
a*d + b*c + e
三元式
四元式
(1) (*, a, d) (2) (*, b, c) (3) (+, (1), (2)) (4) (+, (3), e)
(*, a, d, t1) (*, b, c, t2) (+, t1, t2, t3) (+, t3, e, t4)
操作分量的抽象地址
操作分量
常量: 整数或者实数 标号: 标号名 变量: 需要更多信息用于形成其目标地址 函数/过程:需要更多信息用于得到其代码的目标地址
操作分量的ARG结构 --- 抽象地址结构
常量: (valKind, C) 标号: (labelKind, label) 变量: (varKind, level, offset, mode) 函数/过程:
生成后缀式的例子
中缀式: a * d + b * c + e #
运算符栈 S1
运算分量栈 S2
注意: 任何运算符的优先级都大于 ‘(’; (1)初始化: S1和S2为空; (2) 读token: tk=ReadOne(); (3) Switch tk of (i) #: if (S1为空) exit; else while (S1不为空) /*产生剩余操作符的后缀表示*/ {op = pop(S1); (str1, str2)=pop(2); push(S2, str2 + str1 + “op” );} (ii)operand: push(tk, S2); goto (2); ‘(’ : push(‘(‘, S1); goto (2); (iii)operator: if (S1为空 || tk优先级大于Top(S1)) { push (tk, S1);goto(2); } else { while(tk小于等于Top(S1) && Top(S1) ≠ ‘(’ && S1不为空))) { op = pop(S1); (str1, str2)=pop(2); push(S2, str2+str1 + “op”); } push(tk, S1); goto (2);} } (iv) ‘)’: while (Top(S1) ≠ ‘(’ ) {op = pop(S1); (str1, str2)=pop(2); push(S2, str2+str1 + “op”);} pop(S1); goto (2);
中缀 (运算符在操作数的中间) a*b 前缀式(运算符在操作数的前面) *ab 后缀式(运算符在操作数的后面) ab*
由抽象语法树生成后缀式
中缀式: a*d + b*c + e
+ + * a d b * e 后根遍历生成后缀式:
ad*bc*+e+
先根遍历生成前缀式:
中间代码生成在编译器中的作用
词法分析 目标代码生成
语法分析
中间代码优化
语义分析
中间代码生成
分析
合成
中间代码生成
中间代码生成是将源程序翻译成中间表示的 过程 目的:增强语言的可移植性、进行优化; 中间代码生成方法:
语法制导的翻译方法:属性文法和动作文法 基于Token序列
基于抽象语法树
由Token序列生成后缀式(2)
带括号表达式的后缀式例子
中缀式: (a + (d + b) * c ) + e #
后缀式: a d b + c * +e +
Operator stack 运算符栈 S1
Operand stack
运算源自文库量栈 S2
7.1 常见的中间表示
抽象语法树-AST 无环有向图-DAG(共享的AST)
中间代码生成
M1
源程序
词 法 Token 分 析 序列 器
语 法 语法 分 分析 析 树 器
语 义 分 析 器
中 间 代 中间代码 码 生 成 器
…
Mn
7.1 常见的中间表示
后缀式,逆波兰式 抽象语法树 无环有向图 三元式
四元式
三地址中间代码
7.1 常见的中间表示
后缀式(逆波兰式)
+ +
a*c + a*c + e
e
+ +
e
* a
c a AST
* c a
* c
* a
DAG c
7.1 常见的中间表示
三地址中间代码
三地址:两个操作分量和一个结果的抽象地址; 为方便起见, 通常用变量名代替抽象地址; 三元式 No. (op, operand1, operand2) 编号 (操作符, 操作分量1, 操作分量2) 其中操作分量可以是变量名(抽象地址)或者编号 四元式 (op, operand1, operand2, result) (操作符, 操作分量1, 操作分量2, 结果) 其中操作分量可以是变量名(抽象地址)或者临时变量 (抽象地址)
实在函数/过程: (funKind, actual, label) 形参函数/过程: (funKind, formal, level, offset)
c
++*ad*bce
抽象语法树
由Token序列生成后缀式(1)
(1)初始化: S1和S2为空; (2) 读token: tk=ReadOne(); (3) Switch tk of (i) #: if (S1为空) exit; else while (S1不为空) /*产生剩余操作符的后缀表示*/ {op = pop(S1); (str1, str2)=pop(2); push(S2, str2 + str1+ “op”);} (ii)运算分量: push(tk, S2); goto (2); (iii)运算符: if (S1为空 || tk优先级大于Top(S1)) { push (tk, S1); goto(2);} else { while(tk小于等于Top(S1) && S1不为空)) { op = pop(S1); (str1, str2)=pop(2); push(S2, str2+str1 + “op”); } push(tk, S1); goto (2); }
三地址代码的例子
a*d + b*c + e
三元式
四元式
(1) (*, a, d) (2) (*, b, c) (3) (+, (1), (2)) (4) (+, (3), e)
(*, a, d, t1) (*, b, c, t2) (+, t1, t2, t3) (+, t3, e, t4)
操作分量的抽象地址
操作分量
常量: 整数或者实数 标号: 标号名 变量: 需要更多信息用于形成其目标地址 函数/过程:需要更多信息用于得到其代码的目标地址
操作分量的ARG结构 --- 抽象地址结构
常量: (valKind, C) 标号: (labelKind, label) 变量: (varKind, level, offset, mode) 函数/过程:
生成后缀式的例子
中缀式: a * d + b * c + e #
运算符栈 S1
运算分量栈 S2
注意: 任何运算符的优先级都大于 ‘(’; (1)初始化: S1和S2为空; (2) 读token: tk=ReadOne(); (3) Switch tk of (i) #: if (S1为空) exit; else while (S1不为空) /*产生剩余操作符的后缀表示*/ {op = pop(S1); (str1, str2)=pop(2); push(S2, str2 + str1 + “op” );} (ii)operand: push(tk, S2); goto (2); ‘(’ : push(‘(‘, S1); goto (2); (iii)operator: if (S1为空 || tk优先级大于Top(S1)) { push (tk, S1);goto(2); } else { while(tk小于等于Top(S1) && Top(S1) ≠ ‘(’ && S1不为空))) { op = pop(S1); (str1, str2)=pop(2); push(S2, str2+str1 + “op”); } push(tk, S1); goto (2);} } (iv) ‘)’: while (Top(S1) ≠ ‘(’ ) {op = pop(S1); (str1, str2)=pop(2); push(S2, str2+str1 + “op”);} pop(S1); goto (2);