当前位置:首页 » 编程软件 » 编译技术答案

编译技术答案

发布时间: 2022-08-20 07:06:44

编译原理求解答案

编译原理是计算机软件专业中的非常重要一门课程。例如:如何把我们编写的高级语言源程序,翻译成机器可执行的目标程序,这个就需要用到编译原理技术。

但是学习编译原理这门课程时,是需要头脑中对编译原理课程中涉及到的所有概念必须是相当清楚的,别人才能够对你的这些问题进行准确的回答。而不是看到这些似曾亲切的内容就敢于回答你的内容的。
故我个人的建议还是:你可以向专门讲授编译原理的老师请教你的问题。
以上就是我很多年前学习编译原理的亲身体会。

⑵ 把编译程序设计原理(第二版)高等教育出版社的课后答案给我发一份 可以吗

目录
第1章编译器概述
1.1为什么要学习编译技术
1.2编译器和解释器
1.3编译器的功能分解和组织结构
1.4编译器的伙伴
1.5编译器的复杂性
1.6编译器的设计与实现
1.7编译器的测试与维护
第2章一个微型编译器
2.1基础知识
2.2ToyL语言
2.3ToyL语言词法分析器
2.4ToyL语言语法分析器
2.5ToyL语言解释器
2.6ToyL语言编译器
第3章有穷自动机与词法分析
3.1词法分析基础
3.1.1词法分析器的功能
3.1.2单词识别
3.1.3词法分析的复杂性
3.1.4字符串
3.1.5保留字处理
3.1.6空格符、回车符、换行符
3.1.7括号类配对预检
3.1.8词法错误修正
3.1.9词法分析独立化的意义
3.2有穷自动机
3.2.1确定有穷自动机的定义
3.2.2确定有穷自动机的实现
3.2.3非确定有穷自动机
3.2.4NFA到DFA的转换
3.2.5确定有穷自动机的极小化
3.2.6自动机状态转换表的实现
3.3正则表达式
3.3.1正则符号串集
3.3.2正则表达式的定义
3.3.3正则表达式的局限性
3.3.4正则定义
3.3.5正则表达式到有穷自动机的转换
3.4词法分析器的构造
3.4.1用DFA人工构造词法分析器
3.4.2词法分析器的生成器Lex
练习
第4章文法与语法分析
4.1语法分析
4.1.1语法分析器的输入
4.1.2语法分析的任务
4.1.3语法分析方法分类
4.2文法和文法分析
4.2.1上下文无关文法和语言
4.2.2最左推导和最右推导
4.2.3语法分析树与二义性
4.2.4文法分析算法
4.2.5自顶向下方法概述
4.2.6自底向上方法概述
4.3递归下降法——自顶向下分析
4.3.1递归下降法原理
4.3.2消除公共前缀
4.3.3代入
4.3.4消除左递归
4.4LL分析方法——自顶向下分析
4.4.1LL(1)文法
4.4.2LL(1)分析表
4.4.3LL(1)分析的驱动器
4.4.4LL(1)中的If-Then-Else问题
4.4.5LL(1)分析器的自动生成器LLGen
4.4.6LL(1)分析法与递归下降法的比较
4.4.7正则文法
4.5LR方法——自底向上分析
4.5.1句柄
4.5.2活前缀
4.5.3归约活前缀识别器——LR(0)自动机
4.5.4LR(0)文法及其分析算法
4.5.5SLR(1)文法及其分析算法
4.5.6LR(1)文法
4.5.7LALR(1)文法
4.5.8二义性文法的处理
4.5.9另一种Shift-Rece分析技术:简单优先法
4.5.10LL(1)和LALR(1)方法比较
4.6LR分析器的生成器
4.6.1LALR分析器的生成器YACC
4.6.2LALR分析器的生成器LALRGen
4.7语法错误处理
4.7.1错误恢复和修复
4.7.2递归下降分析的错误恢复
4.7.3LL分析的错误恢复
4.7.4LR分析的错误恢复
练习
第5章语义分析
5.1语义分析基础
5.1.1语义分析内容
5.1.2标识符信息的内部表示
5.1.3类型信息的内部表示
5.1.4运行时值的表示
5.2符号表
5.2.1符号表查找技术
5.2.2符号表的局部化
5.2.3二叉式局部符号表
5.2.4散列式全局符号表
5.2.5嵌套式全局符号表
5.2.6符号表界面函数
5.3类型分析
5.3.1类型的等价性和相容性
5.3.2类型分析的总控算法
5.3.3类型名分析
5.3.4枚举类型分析
5.3.5数组类型分析
5.3.6记录类型分析
5.3.7联合类型分析
5.3.8指针类型分析
5.3.9递归类型分析
5.4声明的语义分析
5.4.1声明的语法结构
5.4.2标号声明部分的语义分析
5.4.3常量声明部分的语义分析
5.4.4类型声明部分的语义分析
5.4.5变量声明部分的语义分析
5.4.6过程、函数声明的语义分析
5.5执行体的语义分析
5.5.1执行体的语义分析
5.5.2带标号语句和转向语句的语义分析
5.5.3赋值语句的语义分析
5.5.4条件语句的语义分析
5.5.5while循环语句的语义分析
5.5.6for循环语句的语义分析
5.5.7过程调用语句的语义分析
5.5.8表达式的语义分析
5.5.9变量的语义分析
练习
第6章运行时的存储环境
6.1运行时的存储空间结构与分配
6.1.1运行时的存储空间基本结构
6.1.2静态区的存储分配
6.1.3栈区的存储分配
6.1.4堆区的存储分配
6.1.5堆区空间管理
6.2过程活动记录与栈区组织结构
6.2.1过程活动记录
6.2.2活动记录的填写
6.2.3栈区组织结构——AR链
6.3运行时的变量访问环境
6.3.1可访问活动记录
6.3.2局部Display表方法
6.3.3静态链方法
6.3.4全局Display表方法和寄存器方法
6.3.5无嵌套时的AR及访问环境
6.4分程序和动态数组空间
6.4.1无动态数组时的分程序空间
6.4.2动态数组空间
练习
第7章面向语法的语义描述
7.1动作文法
7.1.1动作文法定义
7.1.2动作文法的递归实现
7.1.3动作文法的LL实现
7.1.4动作文法的LR实现
7.2动作文法应用
7.2.1用动作文法描述表达式计算
7.2.2用动作文法描述表达式抽象树的构造
7.2.3用动作文法描述语句抽象树的构造
7.3抽象动作文法及其应用
7.3.1抽象变量
7.3.2抽象动作文法
7.3.3栈式LL动作文法驱动器
7.3.4抽象动作文法到栈式LL动作文法的转换
7.3.5栈式LR动作文法驱动器
7.3.6抽象动作文法到栈式LR动作文法的转换
7.4属性文法
7.4.1属性文法定义
7.4.2属性语法树和属性依赖图
7.4.3计算顺序
7.4.4属性值的计算方法
7.4.5拷贝型属性文法
7.5属性文法在编译器设计中的应用
7.5.1类型树的属性文法描述
7.5.2表达式中间代码的属性文法描述
7.5.3变量中间代码的属性文法描述
7.5.4语句中间代码的属性文法描述
7.5.5正则表达式到自动机转换的属性文法描述
7.6S-属性文法及其属性计算
7.6.1S-属性文法
7.6.2S-属性文法的递归实现
7.6.3S-属性文法的LR实现
7.7L-属性文法及其属性计算
7.7.1L-属性文法
7.7.2L-属性文法的递归实现
7.7.3L-属性文法的LR(1)实现
7.8语义分析器的自动生成系统
7.8.1YACC
7.8.2LALRGen
7.8.3Accent系统
练习
第8章中间代码生成
8.1中间代码
8.1.1中间代码的种类
8.1.2后缀式中间代码
8.1.3三地址中间代码
8.1.4抽象语法树和无环有向图
8.1.5多元式中间代码
8.1.6中间代码分量ARG结构
8.2表达式的中间代码生成
8.2.1表达式的语义信息
8.2.2表达式的中间代码
8.2.3变量的中间代码
8.2.4表达式的中间代码生成
8.2.5变量的中间代码生成
8.2.6布尔表达式的短路中间代码
8.3原子语句的中间代码生成
8.3.1输入/输出语句的中间代码生成
8.3.2goto语句和标号定位语句的中间代码生成
8.3.3return语句的中间代码生成
8.3.4赋值语句的中间代码生成
8.3.5函数(过程)调用的中间代码生成
8.4结构语句的中间代码生成
8.4.1条件语句的中间代码生成
8.4.2while语句的中间代码生成
8.4.3repeat语句的中间代码生成
8.4.4for语句的中间代码生成
8.4.5case语句的中间代码生成
8.4.6函数声明的中间代码生成
练习
第9章中间代码优化
9.1引言
9.1.1优化的目标和要求
9.1.2优化的必要性
9.1.3优化的内容
9.1.4局部优化和全局优化
9.1.5基本块和程序流图
9.2常表达式优化
9.2.1常表达式的局部优化
9.2.2基于常量定值分析的常表达式全局优化
9.2.3常量定值分析
9.3公共表达式优化
9.3.1基于相似性的公共表达式局部优化
9.3.2基于值编码的公共表达式局部优化
9.3.3基于活跃代码分析的公共表达式全局优化
9.3.4活跃运算代码分析
9.4程序流图循环
9.4.1循环的基本概念
9.4.2支撑结点
9.4.3自然循环
9.4.4可归约程序流图
9.4.5基于文本的循环及其处理
9.5循环不变代码外提
9.5.1代码外提的基本概念
9.5.2循环不变代码的判定
9.5.3循环不变代码外提的条件
9.5.4基于文本循环和定值表的不变代码外提
9.5.5一种简单的外提优化方案
9.5.6别名分析
9.5.7过程与函数的副作用分析
9.6循环内归纳表达式的优化
9.6.1归纳变量
9.6.2归纳变量计算的优化算法原理
练习
第10章目标代码生成
10.1目标代码
10.1.1虚拟机代码
10.1.2目标机代码
10.1.3窥孔优化
10.2临时变量
10.2.1临时变量的特点
10.2.2临时变量的存储空间
10.2.3临时变量的存储分配
10.2.4变量状态描述
10.3寄存器
10.3.1寄存器分类及其使用准则
10.3.2寄存器分配单位
10.3.3寄存器状态描述
10.3.4寄存器分配算法
10.4基于三地址中间代码的目标代码生成
10.4.1目标地址生成
10.4.2间接目标地址的转换
10.4.3表达式中间代码的目标代码生成
10.4.4赋值中间代码的目标代码生成
10.4.5其他寄存器分配法
10.4.6标号和goto语句中间代码的目标代码生成
10.4.7return中间代码的目标代码生成
10.4.8变量中间代码的目标代码生成
10.4.9函数调用中间代码的目标代码生成
10.5基于AST的代码生成
10.5.1三地址中间代码到AST的转换
10.5.2标记需用寄存器个数
10.5.3从带寄存器个数标记的AST生成代码
10.6基于DAG的代码生成
10.6.1从AST到DAG的转换
10.6.2DAG排序和虚寄存器
10.6.3从带序号和虚寄存器标记的DAG生成代码
10.7代码生成器的自动生成
10.7.1代码生成器的自动化
10.7.2基于指令模板匹配的代码生成技术
10.7.3基于语法分析的代码生成技术
练习
第11章对象式语言的实现
11.1引言
11.2SOOL语法
11.2.1程序
11.2.2分程序
11.2.3类声明
11.2.4类型
11.2.5变量声明
11.2.6函数声明和方法声明
11.2.7语句
11.2.8变量
11.2.9表达式
11.2.10程序示例
11.3SOOL语义
11.3.1声明的作用域
11.3.2Class声明的语义
11.3.3语句的语义
11.4SOOL语义分析
11.4.1标识符的符号表项
11.4.2符号表结构
11.4.3符号表的局部化
11.5SOOL目标代码
11.5.1对象空间
11.5.2当前对象——self
11.5.3活动记录
11.5.4成员变量的目标地址
11.5.5表达式的目标代码
11.5.6Offset原理
11.5.7类的多态性
11.5.8目标代码区
11.5.9方法的动态绑定
11.5.10快速动态绑定目标代码
主要参考文献

⑶ 现代编译原理c语言描述 这本书有答案吗

新手的话建议可以看看谭浩强的C程序设计,基本语法会了,可以看下数据结构和算法,接下来看计算机组成原理-->编译原理-->操作系统-->计算机网络。这些学好了,可以深入研究算法,另外可以看点计算机图形学和人工智能。程序最核心的是算法,所以数学基础要好,不能只能做一辈子码奴。其次英语要好,只要能看懂一般的英文文档就OK了。给你介绍一些书。1、算法计算机程序设计艺术-------Donald.E.Knuth----------算法“倚天屠龙”双剑算法导论-----------------ThomasH.Cormen--------算法“倚天屠龙”双剑离散数学及其应用----------KennethH.Rosen具体数学—计算机科学基础--------Donald.E.Knuth2、数据结构数据结构C++数据结构算法与应用3、C语言C程序设计语言(第2版·新版)---C语言“倚天屠龙双剑”---BrianW.Kernighan“C语言之父”CPrimerPlus中文版(第五版)--------C语言“倚天屠龙双剑”---StephenPrataC程序设计(第三版)---------------------------谭浩强C语言大全(第四版)---------------------------HERBERTSCHILDTC语言接口与实现:创建可重用软件的技术-------------DAVIDR.HANSONC语言参考手册(原书第5版)--------------------------SamuelP.HarbisonC程序设计教程---------------------------------H.M.Deitel/P.J.DeitelC陷阱与缺陷-----------------------------------AndrewKoenig5、C++C++程序设计语言(特别版)---c++八大金刚----BjarneStroustrup“C++之父”C++Primer(第3版)中文版----c++八大金刚---StanleyB.LippmanC++Primer(第4版)中文版----c++八大金刚---StanleyB.LippmanC++标准程序库—自修教程与参考手册--c++八大金刚--NicolaiM.JosuttisC++语言的设计和演化-----c++八大金刚----BjarneStroustrup“C++之父”深度探索C++对象模型---c++八大金刚----StanleyB.LippmanEssentialC++中文版---c++八大金刚---StanleyB.LippmanEffectiveC++中文版2ndEdition-----c++八大金刚------ScottMeyersMoreEffectiveC++中文版----c++八大金刚------ScottMeyersC++编程思想(第2版)第1卷:标准C++导引--------BruceEckelC++编程思想(第2版)第2卷:实用编程技术--------BruceEckelC++程序设计--------------------------谭浩强C++程序设计教程(第2版)--------------钱能C++PrimerPlus(第五版)中文版---StephenPrata6、操作系统深入理解计算机系统(修订版)-------RANDALE.BRYANT计算机操作系统(第六版)7、编译原理跟我一起写makefile《编译原理技术和工具》-------Alfred-------龙书《现代编译原理-C语言描述》-----------AndrewW.Appel-----------虎书《高级编译器设计与实现》-----------StevenS.Muchnick-----------鲸书8、网络计算机网络第四版中文版-----------AndrewS.Tanenbaum-------网络编程三剑客TCP/IP详解3卷本--------------------RichardStevens----网络编程三剑客UNIX网络编程2卷本--------------------RichardStevens----网络编程三剑客用TCP/IP进行网际互联-----------DouglasE.Comer高级TCP/IP编程-------------------JonC.SnaderC++网络编程-----------------------DouglasSchmidtUNIX环境高级编程(第2版)--------------------RichardStevens9、LinuxLinux内核设计与实现Linux内核完全注释LINUX内核分析及编程

⑷ 编译原理及编译程序构造课后习题答案 薛联凤

您好,《普通高校计算机专业精品教材系列:编译原理及编译程序构造(第2版)》介绍编译理论基础及其实现方法,强调语言的形式化定义、编译技术的各种概念及实现过程的具体方法。介绍过程以算法为核心,力求简单明了地反映编译的基础知识。从形式语言理论角度讨论词法分析和语法分析技术,为计算机软件工作者开发大型软件打下良好基础。《普通高校计算机专业精品教材系列:编译原理及编译程序构造(第2版)》以理论联系实际为宗旨,内容深入浅出,重点突出,并结合构造el语言的编译程序介绍一种常用而又简单的编译方法。

⑸ ABCD是集合且均非空集,AxB=CxD,证明A=C且B=D

如下图所示。

离散数学(Discrete mathematics)是研究离散量的结构及其相互关系的数学学科,是现代数学的一个重要分支。


随着信息时代的到来,工业革命时代以微积分为代表的连续数学占主流的地位已经发生了变化,离散数学的重要性逐渐被人们认识。

离散数学课程所传授的思想和方法,广泛地体现在计算机科学技术及相关专业的诸领域,从科学计算到信息处理,从理论计算机科学到计算机应用技术,从计算机软件到计算机硬件,从人工智能到认知系统,无不与离散数学密切相关。

离散的含义是指不同的连接在一起的元素,主要是研究基于离散量的结构和相互间的关系,其对象一般是有限个或可数个元素。

离散数学在各学科领域,特别在计算机科学与技术领域有着广泛的应用,同时离散数学也是计算机专业的专业课程,如程序设计语言、数据结构、操作系统、编译技术、人工智能、数据库、算法设计与分析、理论计算机科学基础等必不可少的先行课程。

⑹ 了解什么叫做jit compiling,与传统的编译技术有何不同

java 应用程序的性能经常成为开发社区中的讨论热点。因为该语言的设计初衷是使用解释的方式支持应用程序的可移植性目标,早期
Java 运行时所提供的性能级别远低于 C 和
C++
之类的编译语言。尽管这些语言可以提供更高的性能,但是生成的代码只能在有限的几种系统上执行。在过去的十年中,Java
运行时供应商开发了一些复杂的动态编译器,通常称作即时(Just-in-time,JIT)编译器。程序运行时,JIT
编译器选择将最频繁执行的方法编译成本地代码。运行时才进行本地代码编译而不是在程序运行前进行编译(用 C 或
C++ 编写的程序正好属于后一情形),保证了可移植性的需求。有些 JIT 编译器甚至不使用解释程序就能编译所有的代码,但是这些编译器仍然通过在程序执行时进行一些操作来保持 Java 应用程序的可移植性。
由于动态编译技术的多项改进,在很多应用程序中,现代的 JIT 编译器可以产生与 C 或 C++
静态编译相当的应用程序性能。但是,仍然有很多软件开发人员认为 —— 基于经验或者传闻 ——
动态编译可能严重干扰程序操作,因为编译器必须与应用程序共享 CPU。一些开发人员强烈呼吁对 Java
代码进行静态编译,并且坚信那样可以解决性能问题。对于某些应用程序和执行环境而言,这种观点是正确的,静态编译可以极大地提高 Java
性能,或者说它是惟一的实用选择。但是,静态地编译 Java 应用程序在获得高性能的同时也带来了很多复杂性。一般的
Java 开发人员可能并没有充分地感受到 JIT 动态编译器的优点。

本文考察了 Java 语言静态编译和动态编译所涉及的一些问题,重点介绍了实时 (RT) 系统。简要描述了 Java
语言解释程序的操作原理并说明了现代 JIT 编译器执行本地代码编译的优缺点。介绍了 IBM 在 WebSphere Real Time 中发布的
AOT 编译技术和它的一些优缺点。然后比较了这两种编译策略并指出了几种比较适合使用 AOT
编译的应用程序领域和执行环境。要点在于这两种编译技术并不互斥:即使在使用这两种技术最为有效的各种应用程序中,它们也分别存在一些影响应用程序的优缺
点。

执行 Java 程序

Java 程序最初是通过 Java SDK 的 javac程序编译成本地的与平台无关的格式(类文件)。可将此格式看作 Java
平台,因为它定义了执行 Java 程序所需的所有信息。Java 程序执行引擎,也称作 Java 运行时环境(JRE),包含了为特定的本地平台实现
Java 平台的虚拟机。例如,基于 Linux 的 Intel x86 平台、Sun Solaris 平台和 AIX 操作系统上运行的 IBM
System p 平台,每个平台都拥有一个 JRE。这些 JRE 实现实现了所有的本地支持,从而可以正确执行为
Java 平台编写的程序。

事实上,操作数堆栈的大小有实际限制,但是编程人员极少编写超出该限制的方法。JVM 提供了安全性检查,对那些创建出此类方法的编程人员进行通知。

Java 平台程序表示的一个重要部分是字节码序列,它描述了 Java
类中每个方法所执行的操作。字节码使用一个理论上无限大的操作数堆栈来描述计算。这个基于堆栈的程序表示提供了平台无关性,因为它不依赖任何特定本地平台
的 CPU 中可用寄存器的数目。可在操作数堆栈上执行的操作的定义都独立于所有本地处理器的指令集。Java
虚拟机(JVM)规范定义了这些字节码的执行(参见 参考资料)。执行 Java 程序时,用于任何特定本地平台的任何 JRE 都必须遵守 JVM
规范中列出的规则。

因为基于堆栈的本地平台很少(Intel X87 浮点数协处理器是一个明显的例外),所以大多数本地平台不能直接执行 Java 字节码。为了解决这个问题,早期的 JRE 通过解释字节码来执行 Java 程序。即 JVM 在一个循环中重复操作:

◆获取待执行的下一个字节码;

◆解码;

◆从操作数堆栈获取所需的操作数;

◆按照 JVM 规范执行操作;

◆将结果写回堆栈。

这种方法的优点是其简单性:JRE 开发人员只需编写代码来处理每种字节码即可。并且因为用于描述操作的字节码少于 255 个,所以实现的成本比较低。当然,缺点是性能:这是一个早期造成很多人对 Java 平台不满的问题,尽管拥有很多其他优点。

解决与 C 或 C++ 之类的语言之间的性能差距意味着,使用不会牺牲可移植性的方式开发用于 Java 平台的本地代码编译。

编译 Java 代码

尽管传闻中 Java 编程的 “一次编写,随处运行”
的口号可能并非在所有情况下都严格成立,但是对于大量的应用程序来说情况确实如此。另一方面,本地编译本质上是特定于平台的。那么 Java
平台如何在不牺牲平台无关性的情况下实现本地编译的性能?答案就是使用 JIT 编译器进行动态编译,这种方法已经使用了十年(参见图 1):

图 1. JIT 编译器

使用 JIT 编译器时,Java
程序按每次编译一个方法的形式进行编译,因为它们在本地处理器指令中执行以获得更高的性能。此过程将生成方法的一个内部表示,该表示与字节码不同但是其级
别要高于目标处理器的本地指令。(IBM JIT
编译器使用一个表达式树序列表示方法的操作。)编译器执行一系列优化以提高质量和效率,最后执行一个代码生成步骤将优化后的内部表示转换成目标处理器的本
地指令。生成的代码依赖运行时环境来执行一些活动,比如确保类型转换的合法性或者对不能在代码中直接执行的某些类型的对象进行分配。JIT
编译器操作的编译线程与应用程序线程是分开的,因此应用程序不需要等待编译的执行。

图 1 中还描述了用于观察执行程序行为的分析框架,通过周期性地对线程取样找出频繁执行的方法。该框架还为专门进行分析的方法提供了工具,用来存储程序的此次执行中可能不会改变的动态值。

因为这个 JIT 编译过程在程序执行时发生,所以能够保持平台无关性:发布的仍然是中立的 Java 平台代码。C 和 C++ 之类的语言缺乏这种优点,因为它们在程序执行前进行本地编译;发布给(本地平台)执行环境的是本地代码。

挑战

尽管通过 JIT 编译保持了平台无关性,但是付出了一定代价。因为在程序执行时进行编译,所以编译代码的时间将计入程序的执行时间。任何编写过大型 C 或 C++ 程序的人都知道,编译过程往往较慢。

为了克服这个缺点,现代的 JIT
编译器使用了下面两种方法的任意一种(某些情况下同时使用了这两种方法)。第一种方法是:编译所有的代码,但是不执行任何耗时多的分析和转换,因此可以快
速生成代码。由于生成代码的速度很快,因此尽管可以明显观察到编译带来的开销,但是这很容易就被反复执行本地代码所带来的性能改善所掩盖。第二种方法是:
将编译资源只分配给少量的频繁执行的方法(通常称作热方法)。低编译开销更容易被反复执行热代码带来的性能优势掩盖。很多应用程序只执行少量的热方法,因
此这种方法有效地实现了编译性能成本的最小化。

动态编译器的一个主要的复杂性在于权衡了解编译代码的预期获益使方法的执行对整个程序的性能起多大作用。一个极端的例子是,程序执行后,您非常清楚哪些方
法对于这个特定的执行的性能贡献最大,但是编译这些方法毫无用处,因为程序已经完成。而在另一个极端,程序执行前无法得知哪些方法重要,但是每种方法的潜
在受益都最大化了。大多数动态编译器的操作介于这两个极端之间,方法是权衡了解方法预期获益的重要程度。

Java 语言需要动态加载类这一事实对 Java
编译器的设计有着重要的影响。如果待编译代码引用的其他类还没有加载怎么办?比如一个方法需要读取某个尚未加载的类的静态字段值。Java
语言要求第一次执行类引用时加载这个类并将其解析到当前的 JVM
中。直到第一次执行时才解析引用,这意味着没有地址可供从中加载该静态字段。编译器如何处理这种可能性?编译器生成一些代码,用于在没有加载类时加载并解
析类。类一旦被解析,就会以一种线程安全的方式修改原始代码位置以便直接访问静态字段的地址,因为此时已获知该地址。

IBM JIT
编译器中进行了大量的努力以便使用安全而有效率的代码补丁技术,因此在解析类之后,执行的本地代码只加载字段的值,就像编译时已经解析了字段一样。另外一
种方法是生成一些代码,用于在查明字段的位置以前一直检查是否已经解析字段,然后加载该值。对于那些由未解析变成已解析并被频繁访问的字段来说,这种简单
的过程可能带来严重的性能问题。

动态编译的优点

动态地编译 Java 程序有一些重要的优点,甚至能够比静态编译语言更好地生成代码,现代的 JIT 编译器常常向生成的代码中插入挂钩以收集有关程序行为的信息,以便如果要选择方法进行重编译,就可以更好地优化动态行为。

关于此方法的一个很好的例子是收集一个特定 array操作的长度。如果发现每次执行操作时该长度基本不变,则可以为最频繁使用的

array长度生成专门的代码,或者可以调用调整为该长度的代码序列。由于内存系统和指令集设计的特性,用于复制内存的最佳通用例程的执行速度通
常比用于复制特定长度的代码慢。例如,复制 8
个字节的对齐的数据可能需要一到两条指令直接复制,相比之下,使用可以处理任意字节数和任意对齐方式的一般复制循环可能需要 10 条指令来复制同样的 8

个字节。但是,即使此类专门的代码是为某个特定的长度生成的,生成的代码也必须正确地执行其他长度的复制。生成代码只是为了使常见长度的操作执行得更快,
因此平均下来,性能得到了改进。此类优化对大多数静态编译语言通常不实用,因为所有可能的执行中长度恒定的操作比一个特定程序执行中长度恒定的操作要少得
多。

此类优化的另一个重要的例子是基于类层次结构的优化。例如,一个虚方法调用需要查看接收方对象的类调用,以便找出哪个实际目标实现了接收方对象的虚方法。
研究表明:大多数虚调用只有一个目标对应于所有的接收方对象,而 JIT
编译器可以为直接调用生成比虚调用更有效率的代码。通过分析代码编译后类层次结构的状态,JIT
编译器可以为虚调用找到一个目标方法,并且生成直接调用目标方法的代码而不是执行较慢的虚调用。当然,如果类层次结构发生变化,并且出现另外的目标方法,
则 JIT
编译器可以更正最初生成的代码以便执行虚调用。在实践中,很少需要作出这些更正。另外,由于可能需要作出此类更正,因此静态地执行这种优化非常麻烦。

因为动态编译器通常只是集中编译少量的热方法,所以可以执行更主动的分析来生成更好的代码,使编译的回报更高。事实上,大部分现代的
JIT
编译器也支持重编译被认为是热方法的方法。可以使用静态编译器(不太强调编译时间)中常见的非常主动的优化来分析和转换这些频繁执行的方法,以便生成更好
的代码并获得更高的性能。

这些改进及其他一些类似的改进所产生的综合效果是:对于大量的 Java 应用程序来说,动态编译已经弥补了与 C 和 C++ 之类语言的静态本地编译性能之间的差距,在某些情况下,甚至超过了后者的性能。

缺点

但是,动态编译确实具有一些缺点,这些缺点使它在某些情况下算不上一个理想的解决方案。例如,因为识别频繁执行的方法以及编译这些方法需要时间,所以应用
程序通常要经历一个准备过程,在这个过程中性能无法达到其最高值。在这个准备过程中出现性能问题有几个原因。首先,大量的初始编译可能直接影响应用程序的
启动时间。不仅这些编译延迟了应用程序达到稳定状态的时间(想象 Web
服务器经
历一个初始阶段后才能够执行实际有用的工作),而且在准备阶段中频繁执行的方法可能对应用程序的稳定状态的性能所起的作用也不大。如果 JIT
编译会延迟启动又不能显着改善应用程序的长期性能,则执行这种编译就非常浪费。虽然所有的现代 JVM
都执行调优来减轻启动延迟,但是并非在所有情况下都能够完全解决这个问题。

其次,有些应用程序完全不能忍受动态编译带来的延迟。如 GUI 接口之类交互式应用程序就是这样的例子。在这种情况下,编译活动可能对用户使用造成不利影响,同时又不能显着地改善应用程序的性能。

最后,用于实时环境并具有严格的任务时限的应用程序可能无法忍受编译的不确定性性能影响或动态编译器本身的内存开销。

因此,虽然 JIT 编译技术已经能够提供与静态语言性能相当(甚至更好)的性能水平,但是动态编译并不适合于某些应用程序。在这些情况下,Java 代码的提前(Ahead-of-time,AOT)编译可能是合适的解决方案。

AOT Java 编译

大致说来,Java 语言本地编译应该是为传统语言(如 C++ 或
Fortran)而开发的编译技术的一个简单应用。不幸的是,Java 语言本身的动态特性带来了额外的复杂性,影响了 Java
程序静态编译代码的质量。但是基本思想仍然是相同的:在程序执行前生成 Java 方法的本地代码,以便在程序运行时直接使用本地代码。目的在于避免
JIT 编译器的运行时性能消耗或内存消耗,或者避免解释程序的早期性能开销。

挑战

动态类加载是动态 JIT 编译器面临的一个挑战,也是 AOT
编译的一个更重要的问题。只有在执行代码引用类的时候才加载该类。因为是在程序执行前进行 AOT
编译的,所以编译器无法预测加载了哪些类。就是说编译器无法获知任何静态字段的地址、任何对象的任何实例字段的偏移量或任何调用的实际目标,甚至对直接调
用(非虚调用)也是如此。在执行代码时,如果证明对任何这类信息的预测是错误的,这意味着代码是错误的并且还牺牲了 Java 的一致性。

因为代码可以在任何环境中执行,所以类文件可能与代码编译时不同。例如,一个 JVM
实例可能从磁盘的某个特定位置加载类,而后面一个实例可能从不同的位置甚至网络加载该类。设想一个正在进行 bug
修复的开发环境:类文件的内容可能随不同的应用程序的执行而变化。此外,Java 代码可能在程序执行前根本不存在:比如 Java
反射服务通常在运行时生成新类来支持程序的行为。

缺少关于静态、字段、类和方法的信息意味着严重限制了 Java 编译器中优化框架的大部分功能。内联可能是静态或动态编译器应用的最重要的优化,但是由于编译器无法获知调用的目标方法,因此无法再使用这种优化。

内联

内联是一种用于在运行时生成代码避免程序开始和结束时开销的技术,方法是将函数的调用代码插入到调用方的函数中。但是内联最大的益处可能是优化方可见的代码的范围扩大了,从而能够生成更高质量的代码。下面是一个内联前的代码示例:

int foo() { int x=2, y=3; return bar(x,y); }final int bar(int a, int b) { return a+b; }

如果编译器可以证明这个 bar就是 foo()中调用的那个方法,则 bar中的代码可以取代 foo()中对
bar()的调用。这时,bar()方法是 final类型,因此肯定是 foo()中调用的那个方法。甚至在一些虚调用例子中,动态 JIT
编译器通常能够推测性地内联目标方法的代码,并且在绝大多数情况下能够正确使用。编译器将生成以下代码:

int foo() { int x=2, y=3; return x+y; }

在这个例子中,简化前名为值传播的优化可以生成直接返回
5的代码。如果不使用内联,则不能执行这种优化,产生的性能就会低很多。如果没有解析
bar()方法(例如静态编译),则不能执行这种优化,而代码必须执行虚调用。运行时,实际调用的可能是另外一个执行两个数字相乘而不是相加的
bar方法。所以不能在 Java 程序的静态编译期间直接使用内联。

AOT
代码因此必须在没有解析每个静态、字段、类和方法引用的情况下生成。执行时,每个这些引用必须利用当前运行时环境的正确值进行更新。这个过程可能直接影响
第一次执行的性能,因为在第一次执行时将解析所有引用。当然,后续执行将从修补代码中获益,从而可以更直接地引用实例、静态字段或方法目标。

另外,为 Java 方法生成的本地代码通常需要使用仅在单个 JVM 实例中使用的值。例如,代码必须调用 JVM
运行时中的某些运行时例程来执行特定操作,如查找未解析的方法或分配内存。这些运行时例程的地址可能在每次将 JVM 加载到内存时变化。因此 AOT
编译代码需要绑定到 JVM 的当前执行环境中,然后才能执行。其他的例子有字符串的地址和常量池入口的内部位置。

在 WebSphere Real Time 中,AOT 本地代码编译通过 jxeinajar工具(参见图 2)来执行。该工具对 JAR 文件中所有类的所有方法应用本地代码编译,也可以选择性地对需要的方法应用本地代码编译。结果被存储到名为 Java eXEcutable (JXE) 的内部格式中,但是也可轻松地存储到任意的持久性容器中。

您可能认为对所有的代码进行静态编译是最好的方法,因为可以在运行时执行最大数量的本地代码。但是此处可以作出一些权衡。编译的方法越多,代码占用的内存
就越多。编译后的本地代码大概比字节码大 10 倍:本地代码本身的密度比字节码小,而且必须包含代码的附加元数据,以便将代码绑定到 JVM
中,并且在出现异常或请求堆栈跟踪时正确执行代码。构成普通 Java 应用程序的 JAR
文件通常包含许多很少执行的方法。编译这些方法会消耗内存却没有什么预期收益。相关的内存消耗包括以下过程:将代码存储到磁盘上、从磁盘取出代码并装入
JVM,以及将代码绑定到 JVM。除非多次执行代码,否则这些代价不能由本地代码相对解释的性能优势来弥补。

图 2. jxeinajar

跟大小问题相违背的一个事实是:在编译过的方法和解释过的方法之间进行的调用(即编译过的方法调用解释过的方法,或者相反)可能比这两类方法各自内部之间
进行的调用所需的开销大。动态编译器通过最终编译所有由 JIT
编译代码频繁调用的那些解释过的方法来减少这项开销,但是如果不使用动态编译器,则这项开销就不可避免。因此如果是选择性地编译方法,则必须谨慎操作以使
从已编译方法到未编译方法的转换最小化。为了在所有可能的执行中都避免这个问题而选择正确的方法会非常困难。
优点
虽然 AOT 编译代码具有上述的缺点和挑战,但是提前编译 Java 程序可以提高性能,尤其是在不能将动态编译器作为有效解决方案的环境中。

可以通过谨慎地使用 AOT 编译代码加快应用程序启动,因为虽然这种代码通常比 JIT
编译代码慢,但是却比解释代码快很多倍。此外,因为加载和绑定 AOT
编译代码的时间通常比检测和动态编译一个重要方法的时间少,所以能够在程序执行的早期达到那样的性能。类似地,交互式应用程序可以很快地从本地代码中获
益,无需使用引起较差响应能力的动态编译。

RT 应用程序也能从 AOT 编译代码中获得重要的收益:更具确定性的性能超过了解释的性能。WebSphere Real Time
使用的动态 JIT 编译器针对在 RT 系统中的使用进行了专门的调整。使编译线程以低于 RT
任务的优先级操作,并且作出了调整以避免生成带有严重的不确定性性能影响的代码。但是,在一些 RT 环境中,出现 JIT
编译器是不可接受的。此类环境通常需要最严格的时限管理控制。在这些例子中,AOT
编译代码可以提供比解释过的代码更好的原始性能,又不会影响现有的确定性。消除 JIT
编译线程甚至消除了启动更高优先级 RT 任务时发生的线程抢占所带来的性能影响。

优缺点统计

动态(JIT)编译器支持平台中立性,并通过利用应用程序执行的动态行为和关于加载的类及其层次结构的信息来生成高质量的代码。但是
JIT
编译器具有一个有限的编译时预算,而且会影响程序的运行时性能。另一方面,静态(AOT)编译器则牺牲了平台无关性和代码质量,因为它们不能利用程序的动
态行为,也不具有关于加载的类或类层次结构的信息。AOT 编译拥有有效无限制的编译时预算,因为 AOT
编译时间不会影响运行时性能,但是在实践中开发人员不会长期等待静态编译步骤的完成。

表 1 总结了本文讨论的 Java 语言动态和静态编译器的一些特性:

表 1. 比较编译技术

两种技术都需要谨慎选择编译的方法以实现最高的性能。对动态编译器而言,编译器自身作出决策,而对于静态编译器,由开发人员作出选择。让
JIT 编译器选择编译的方法是不是优点很难说,取决于编译器在给定情形中推断能力的好坏。在大多数情况下,我们认为这是一种优点。

因为它们可以最好地优化运行中的程序,所以 JIT 编译器在提供稳定状态性能方面更胜一筹,而这一点在大量的生产 Java
系统中最为重要。静态编译可以产生最佳的交互式性能,因为没有运行时编译行为来影响用户预期的响应时间。通过调整动态编译器可以在某种程度上解决启动和确
定性性能问题,但是静态编译在需要时可提供最快的启动速度和最高级别的确定性。表 2 在四种不同的执行环境中对这两种编译技术进行了比较:

表 2. 使用这些技术的最佳环境

图 3 展示了启动性能和稳定状态性能的总体趋势:

图 3. AOT 和 JIT 的性能对比

使用 JIT 编译器的初始阶段性能很低,因为要首先解释方法。随着编译方法的增多及 JIT
执行编译所需时间的缩短,性能曲线逐渐升高最后达到性能峰值。另一方面,AOT 编译代码启动时的性能比解释的性能高很多,但是无法达到 JIT
编译器所能达到的最高性能。将静态代码绑定到 JVM 实例中会产生一些开销,因此开始时的性能比稳定状态的性能值低,但是能够比使用 JIT
编译器更快地达到稳定状态的性能水平。

没有一种本地代码编译技术能够适合所有的 Java
执行环境。某种技术所擅长的通常正是其他技术的弱项。出于这个原因,需要同时使用这两种编译技术以满足 Java
应用程序开发人员的要求。事实上,可以结合使用静态和动态编译以便提供最大可能的性能提升 —— 但是必须具备平台无关性,它是 Java
语言的主要卖点,因此不成问题。

结束语

本文探讨了 Java 语言本地代码编译的问题,主要介绍了 JIT 编译器形式的动态编译和静态 AOT 编译,比较了二者的优缺点。

虽然动态编译器在过去的十年里实现了极大的成熟,使大量的各种 Java 应用程序可以赶上或超过静态编译语言(如 C++ 或
Fortran)所能够达到的性能。但是动态编译在某些类型的应用程序和执行环境中仍然不太合适。虽然 AOT
编译号称动态编译缺点的万能解决方案,但是由于 Java 语言本身的动态特性,它也面临着提供本地编译全部潜能的挑战。

这两种技术都不能解决 Java 执行环境中本地代码编译的所有需求,但是反过来又可以在最有效的地方作为工具使用。这两种技术可以相互补充。能够恰当地使用这两种编译模型的运行时系统可以使很大范围内的应用程序开发环境中的开发人员和用户受益。

⑺ 把汇编源程序变成代码程序的过程是()

把汇编源程序变成代码程序的过程是编译。

编译语言不像直译语言一样,由解释器将代码一句一句运行,而是以编译器,先将代码编译为机器码,再加以运行。理论上,任何编程语言都可以是编译式,或直译式的。它们之间的区别,仅与程序的应用有关。

编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。



(7)编译技术答案扩展阅读:

编译技术的发展

在早期冯诺依曼计算机时期 (20世纪40年代) 程序都是以机器语言编写,机器语言就是实际存储的01代码,编写程序是十分枯燥乏味的。

后来汇编语言代替机器语言一符号形式该处操作指令和地址编码。但汇编语言仍有许多缺点, 阅读理解起来很难,而且必须依赖于特定的机器,如果想使编写好的程序在另一台计算机上运行必须重写。

在20世纪50年代IBM的John Backus带领一个研究小组对FORTRAN高级语言及其编译器进行开发。编译程序的自动生成工具初现端倪,现在很多自动生成工具已经广泛使用例如语法分析工具LEX,语言分析程序YACC等。

在20世纪60年代人们不断的用自编译技术构造编译程序,即用被编译的语言本身来实现该语言的编译程序,但其基本原理和结构大体相同。



⑻ 开发大神门帮忙解答一下图中这两道编译技术题,万分感谢!!

实现一个时间类Time。将小时,分钟和秒存储为int型成员变量。要求该类中包含一个构造函数,访问用的函数,一个推进当前时间的函数adv(),一个重新设置当前时间(即将当前时间设为00:00:00)的函数reset()和输出结果函数print()。注意时间按数字式电子表格式显示,即小时、分、秒分别用两位表示,如果其中之一小于10,则前方补0,如22:01:00(中间不含空格),另外按该格式依次输出时、分、秒后,以endl结尾。当输入时间超出合法范围(提示:注意上下界)时,请自动按照24小时制进行转换,如输入25:00:61,则输出应为01:01:01。

#include
using namespace std;
class Time{
public:
Time(int hour,int minute,int second);
Time(){
hour=0;
minute=0;
second=0;
}
void showTime()
{if(second>=60){
minute++;second=second%60;
if(minute>=60){
hour++;minute=minute%60;

热点内容
加密狗是啥 发布:2025-02-06 03:48:03 浏览:552
phpcopy文件 发布:2025-02-06 03:41:26 浏览:410
系统配置页面怎么设置 发布:2025-02-06 03:36:34 浏览:693
家庭电脑搭建流媒体服务器 发布:2025-02-06 03:19:02 浏览:342
matlab稀疏矩阵存储 发布:2025-02-06 03:07:54 浏览:838
国际服2b2t服务器地址 发布:2025-02-06 03:06:28 浏览:390
c语言输出b 发布:2025-02-06 03:06:27 浏览:31
普通火车wifi密码多少 发布:2025-02-06 03:04:20 浏览:436
可编程监控 发布:2025-02-06 03:03:33 浏览:645
c语言取随机数 发布:2025-02-06 02:46:57 浏览:863