六、代码生成,《编译原理》(本科教学版),第2版

文章目录

    • 零、前言
      • 0.1 编译器前端到后端
    • 一、代码生成
      • 1.1 代码生成的任务
      • 1.2 给数据分配计算资源
      • 1.3 给代码选择合适的机器指令
      • 1.4 栈式计算机
        • 1.4.1 栈式计算机Stack的结构
        • 1.4.2 栈计算机的指令集
        • 1.4.3 变量的内存分配伪指令
        • 1.4.4 栈式计算机的代码生成
          • 1.4.4.1 递归下降代码生成算法:从C到Stack
          • 1.4.4.2 递归下降代码生成算法:表达式的代码生成
          • 1.4.4.3 递归下降代码生成算法:语句的代码生成
          • 1.4.4.4 递归下降代码生成算法:类型的代码生成
          • 1.4.4.5 递归下降代码生成算法:变量的代码生成
          • 1.4.4.6 递归下降代码生成算法:程序的代码生成
        • 1.4.5 如何运行生成代码?
      • 1.5 寄存器计算机及其代码生成
        • 1.5.1 寄存器计算机
        • 1.5.2 寄存器计算机Reg的结构
        • 1.5.3 寄存器计算机的指令集
          • 1.5.3.1 变量的寄存器分配伪指令
        • 1.5.4 递归下降代码生成算法:从C到reg
        • 1.5.5 如何运行生成的代码


零、前言

0.1 编译器前端到后端

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

前端对源程序进行进行分析并产生中间表示,后端则在此基础上生成目标代码。

前面几章介绍了编译器前端的主要内容,接下来会进入中间端和后端的部分。

中间端和后端的大致架构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

抽象语法树经过若干次中间表示和翻译,得到汇编代码。这是一个抽象层次逐渐降低的过程。

上世纪七八十年代时的做法是仅通过一次代码生成然后得到汇编,这样的做法由于抽象层次跨度太大,所以实现困难。

现代编译器的选择往往是经过多次生成而向目标代码逐渐靠近。

一、代码生成

1.1 代码生成的任务

  • 负责把源程序翻译成“目标机器”上的代码
    • 目标机器:
      • 可以是真实物理机器
      • 可以是虚拟机
    • 两个重要任务
      • 给源程序的数据分配计算资源
      • 给源程序的代码选择指令

1.2 给数据分配计算资源

  • 源程序的数据
    • 全局变量、局部变量、动态分配等
  • 机器计算资源
    • 寄存器、数据区、代码区、栈区、堆区
  • 根据程序的特点和编译器的设计目标,合理的为数据分配计算资源
    • 例如:变量放在内存里还是寄存器里?

1.3 给代码选择合适的机器指令

  • 源程序的代码
    • 表达式运算、语句、函数等
  • 机器指令
    • 算术运算、比较、跳转、函数调用返回
  • 用机器指令实现高层代码的语义
    • 等价性
    • 对机器指令集体系结构(ISA)的熟悉

我们将研究两种不同的ISA上的代码生成技术

  • 栈计算机Stack
  • 寄存器计算机Reg

1.4 栈式计算机

  • 栈式计算机在历史上非常流行
    • 上世纪70年伐曾有很多栈式计算机
  • 但今天已经基本上已经退出了历史舞台
    • 效率问题
  • 我们还要讨论栈式计算机的代码生成技术的原因是:
    • 给栈式计算机生成代码是最容易的
    • 仍然有许多栈式的虚拟机
      • Pascal P code
      • Java virtual machine (JVM)
      • Postscript
      • ……
1.4.1 栈式计算机Stack的结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 内存
    • 存放所有的变量
    • 进行运算的空间
  • 执行引擎
    • 指令的执行
1.4.2 栈计算机的指令集

指令的语法

s -> push NUM| load x			// 栈操作| store x		// 访存| add| sub		    // 算数运算| times| div

指令的语义:push

NUM push 到栈上,NUM是立即数,不需要访存

push NUM:top ++stack[top] = NUM

指令的语义:load x

从内存读到栈上

load x:top ++stack[top] = x

指令的语义:store x

store x:x = stack[top]top --

指令的语义:add

add:temp = stack[top - 1] + stack[top]top -= 2push temp

指令的语义:sub

sub:temp = stack[top - 1] - stack[top]top -= 2push temp

指令的语义:times

times:temp = stack[top - 1] * stack[top]top -= 2push temp

指令的语义:div

div:temp = stack[top - 1] / stack[top]top -= 2push temp
1.4.3 变量的内存分配伪指令
  • Stack 机器只支持一种数据类型int,并且给变量x分配内存的伪指令是
    • .int x
  • Stack 机器在装载一个程序时,就会读取伪指令,并且给相关变量分配内存空间

示例

int x;
int y;
int z;x = 10;
y = 5;
z = x + y;
y = z * x;

对应的指令为:

.int x
.int y
.int z1: push 10
3: store x
4: push 5
5: store y
6: push x
7: push y
8: add
9: store z
10: load z
11: load x
12: times
13: store y
1.4.4 栈式计算机的代码生成
1.4.4.1 递归下降代码生成算法:从C到Stack
P -> D S
D -> T id; D | 
T -> int| bool
S -> id = E| printi(E)| printb(E)
E -> n| id| true| false| E + E| E && E
Gen_P(D S);
Gen_D(T id; D);
Gen_T(T);
Gen_S(S);
Gen_E(E);

指令的语法

s -> push NUM| load x			// 栈操作| store x		// 访存| add| sub		    // 算数运算| times| div
1.4.4.2 递归下降代码生成算法:表达式的代码生成
// 不变式(始终为真):表达式的值总在栈顶
// emit: 发送指令
Gen_E(E e) switch(e)case n:	emit ("push n"); break;case id: emit ("load id"); break;case true: emit ("push 1"); break;case false: emit ("push 0"); break;case e1 + e2:Gen_E(e1);Gen_E(e2);emit ("add");break;case e1 && e2:Gen_E(e1);Gen_E(e2);emit ("and");break;
1.4.4.3 递归下降代码生成算法:语句的代码生成
// 不变式:栈的规模不变
Gen_S(S s)switch (s)case id=e: Gen_E(e);emit("store id");breakcase printi(e): Gen_E(e);emit("printi")breakcase printb(e): Gen_E(e);emit("printb");break;
1.4.4.4 递归下降代码生成算法:类型的代码生成
Get_T(T t)switch (t)case int: emit(".int");break;case bool: emit(".bool");break;
1.4.4.5 递归下降代码生成算法:变量的代码生成
Get_D(T id; D)Get_T(T);	// -> .int / .boolemit(" id");Gen_D(D);
1.4.4.6 递归下降代码生成算法:程序的代码生成
// 不变式:只生成 .int 类型
Gen_P(D S)Gen_D(D);Gen_S(S);

比如上述程序:

  • 先调用该程序的Gen_P
  • 然后在 Gen_P内调用 Gen_D, Gen_S
  • 在 Gen_D, Gen_S 中在递归调用
1.4.5 如何运行生成代码?
  • 找一台真正的物理机
  • 写一个虚拟机(解释器)
    • 类似于JVM
  • 在 非栈式计算机上进行模拟:
    • 例如,可以在x86上模拟栈式计算机的行为
      • 用x86的调用模拟栈

1.5 寄存器计算机及其代码生成

1.5.1 寄存器计算机
  • 寄存器计算机是目前最流行的机器体系结构之一
    • 效率很高
    • 机器体系结构规整
  • 机器基于寄存器架构
    • 典型的有16、32或者更多个寄存器
      • 所有操作都在寄存器中进行
    • 访存都通过load/store进行
      • 内存不能直接运算
1.5.2 寄存器计算机Reg的结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 内存
    • 存放溢出的变量
  • 寄存器
    • 进行运算的空间
    • 假设有无限多个
  • 执行引擎
    • 指令的执行
1.5.3 寄存器计算机的指令集
// 指令的语法
s -> movn n, r| mov r1, r2			|	数据移动| load [x], r		|| store r, [x]		|	访存| add r1, r2, r3		|| sub r1, r2, r3		|	算术运算| times r1, r2, r3	|| div r1, r2, r3		|
1.5.3.1 变量的寄存器分配伪指令
  • Reg 机器只支持一种数据类型int,并且给变量x分配寄存器的伪指令是:
    • .intx
  • 在代码生成的阶段,假设Reg机器上有无限多个寄存器
    • 因此每个声明变量和临时变量都会占用一个(虚拟)寄存器
    • 把虚拟寄存器分配到物理寄存器的过程称为寄存器分配
1.5.4 递归下降代码生成算法:从C到reg

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Gen_E:

// 不变式:表达式的值在函数返回的寄存器中
R_t Gen_E(E e) switch (e)case n: r = fresh();emit("movn n, r");return r;case id: r = fresh();emit("mov id, r");return r;case true: r = fresh();emit("movn 1, r");return r;case false: r = fresh();emit("movn 0, r");return r;case e1+e2: r1 = Gen_E(e1);r2 = Gen_E(e2);r = fresh();emit("add r1, r2, r3");return r;case e1&&e2: r1 = Gen_E(e1);r2 = Gen_E(e2);r = fresh();emit("and r1, r2, r3");return r;		// 非短路

Gen_S:

Gen_S(S s)switch (s)case id=e: r = Gen_E(e);emit("mov r, id");break;case printi(e): r = Gen_E(e);emit("printi r");break;case printb(e): r = Gen_E(e);emit("printb r");break;

Gen_T:

// 不变式,只生成.int类型
Gen_T(T t)switch (t)case int:	emit (". int");break;case bool:	emit(". int");break;

Gen_D:

// 不变式,只生成.int类型
Gen_D(T id; D)Gen_T(T);emit(" id");Gen_D(D);

Gen_P:

// 不变式,只生成int类型
Gen_P(D S)Gen_D(D);Gen_S(S);

源代码生成了右边的汇编级代码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.5.5 如何运行生成的代码
  • 写一个虚拟机(解释器)
  • 在真实的物理机器上运行
    • 需进行寄存器分配

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/19052.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Android集成FCM(Firebace Cloud Messaging )

集成FCM官方文档 Firebace主页面 将 Firebase 添加到您的 Android 应用 1、进入Firebace页面,创建自己的项目 2、点击自己创建好的项目,在右侧选择Cloud Messaging 3、点击Android去创建 google-services.json 4、将下载的 google-services.json 文件…

D2076——一款双通道音频功率放大器【青牛科技】

概述: D2076是一款双通道音频功率放大器,最低工作电压可到1.0V。适用于 便携式小型收音机或立体声耳机作双通道或BTL应用。 主要特点: BTL工作,Po90mW(典型值) 外接元器件少 通过外接PNP三极管作为…

智慧社区平台系统提升物业管理效率与居民生活质量

内容概要 智慧社区平台系统是为应对现代城市管理挑战而诞生的重要工具。随着城市化进程的加快,传统的物业管理方式已经难以满足日益增长的居民需求和管理复杂性。因此,引入智能化管理手段显得尤为重要。这个系统不仅仅是一个简单的软件,它是…

【langchain4j】AIservices能够实现更加灵活的chain

文章目录 AI service介绍如何工作的AiServices提供的能力支持的返回形式 简单的例子:接收用户消息,并按规定返回接收单个变量接收更多动态变量 advanced RAGChaining multiple AI Services:多个AiSerives合并到一起相关教程:[Lang…

JavaScript 中字符串和数组的概念解析与多角度对比区分

文章目录 💯前言💯字符串(String)💯数组(Array)💯字符串与数组的相同点与不同点💯字符串和数组的实际应用场景💯字符串与数组的互转💯字符串和数组…

4K双模MiniLED显示器哪个好

4K双模MiniLED显示器哪个好?现在市面上的4K双模MiniLED显示器太多了,琳琅满目,今天就给大家列举一下7款当下火热到爆炸的品牌,看看4K双模MiniLED显示器哪个好。 4K双模MiniLED显示器哪个好 - HKC G27M7PRO HKC G27M7Pro 是一款性…

每天五分钟深度学习pytorch:批归一化全连接网络完成手写字体识别

本文重点 前面我们学习了普通的全连接神经网络,后面我们学习了带有激活层的全连接神经网络,本文我们继续进一步升级,我们学习带有批归一化的全连接神经网络,批归一化可以加快神经网络的训练速度,减少过拟合,具体它的原理,大家可以看我们的《每天五分钟深度学习》专栏,…

excel打开csv文件乱码的问题

如图所示,在保存csv文件时已指定编码为utf-8,用excel打开后仍然乱码 解决方法: 在保存csv文件时指定编码为utf-8-sig 该编码方式会在文件开头加入一个 BOM(Byte Order Mark),有助于 Excel 正确识别 UTF-8…

QQ音乐 11.3.4 | 魅族定制版,极致简洁,无广告,不限机型

QQ音乐魅族定制版,界面设计极致简洁,没有任何广告干扰,支持听限免歌曲,不限机型使用。用户可以通过微信和QQ直接登录,享受纯净的音乐体验。 大小:94.6M 下载地址: 百度网盘:https:…

使用TensorFlow实现简化版 GoogLeNet 模型进行 MNIST 图像分类

在本文中,我们将使用 TensorFlow 和 Keras 实现一个简化版的 GoogLeNet 模型来进行 MNIST 数据集的手写数字分类任务。GoogLeNet 采用了 Inception 模块,这使得它在处理图像数据时能更高效地提取特征。本教程将详细介绍如何在 MNIST 数据集上训练和测试这…

TON商城与Telegram App:生态融合与去中心化未来的精彩碰撞

随着区块链技术的快速发展,去中心化应用(DApp)逐渐成为了数字生态的重要组成部分。而Telegram作为全球领先的即时通讯应用,不仅仅满足于传统的社交功能,更在区块链领域大胆探索,推出了基于其去中心化网络的…

vulhub之log4j

Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645) 漏洞简介 Apache Log4j是一个用于Java的日志记录库,其支持启动远程日志服务器。Apache Log4j 2.8.2之前的2.x版本中存在安全漏洞。攻击者可利用该漏洞执行任意代码。 Apache Log4j 在应用程序中添加日志记录最…

web服务nginx实验4:访问控制

4-1:基于不同用户的访问控制: 安装软件: 创建HTTP基本认证用户密码文件,tom,密码:1,lisa,密码:1: -c:表示创建一个新的密码文件。如果该文件已经…

基于FastAPI实现本地大模型API封装调用

关于FastAPI FastAPI 是一个现代、快速(高性能)的 Python Web 框架,用于构建基于标准 Python 类型提示的 API。它以简洁、直观和高效的方式提供工具,特别适合开发现代 web 服务和后端应用程序。 问题:_pad() got an un…

数字化点亮库布其沙漠的绿色梦想

Bentley 应用程序助力提升设计和施工效率,提前六周交付设计成果 清洁能源为沙漠带来新活力 库布其光伏治沙项目(以下简称“该项目”)位于内蒙古鄂尔多斯市库布其沙漠,占地约 10 万亩,是中国单体规模最大的光伏治沙项目…

基于单片机的风能太阳能供电的路灯智能控制系统设计(论文+源码)

1系统总体设计 本课题为风能太阳能供电的路灯智能控制系统设计,系统的主要功能设计如下: (1) 供电模块:采用太阳能板以及风机模拟风扇充电,经过充电电路给锂电池进行充电。再由锂电池给照明模块以及整个项…

Linux Centos7 Rocky网卡配置

目录 1.Vmare 虚拟机配置 (1)打开虚拟机输入ip a,查看ip网段,若为192.168.81.135 (2)在Vmare上的虚拟网络配置器配置 (3)确保电脑有VMnet1 VMnet8 2.Linux虚拟机Centos配置 &#…

MySQL索引原理之查询优化

MySQL索引原理之查询优化 1、慢查询定位 开启慢查询日志 查看 MySQL 数据库是否开启了慢查询日志和慢查询日志文件的存储位置的命令如下: SHOW VARIABLES LIKE %slow_query_log%通过如下命令开启慢查询日志: SET global slow_query_log 1; SET global …

ArchGuard 架构分析器发布:多语言、跨项目架构数据生成,助力 AI 时代知识挖掘...

TL;DR:https://github.com/archguard/archguard 过去的几个月里,我们一直在探索用 AI 辅助跨项目、跨大量微服务的系统的开发。其中一个重要的话题就是,从现有的软件架构去生成知识,文档是落后、多版本的, 只有代码才保…

NLP论文速读(多伦多大学)|利用人类偏好校准来调整机器翻译的元指标

论文速读|MetaMetrics-MT: Tuning Meta-Metrics for Machine Translation via Human Preference Calibration 论文信息: 简介: 本文的背景是机器翻译(MT)任务的评估。在机器翻译领域,由于不同场景和语言对的需求差异&a…