语义及代码生成程序_【原创技术文章】基本程序篇

本文介绍了编程语言的级别,包括低级语言和高级语言,以及它们的区别。深入探讨了编译器和解释器的工作原理,强调了两者在代码优化和执行方式上的差异。此外,详细阐述了Java程序执行过程,以及编译过程的关键步骤,如词法分析、语法分析、语义分析和代码生成,特别提到了三地址码在中间代码生成中的应用。
摘要由CSDN通过智能技术生成
基本程序篇 ea21ce822a490c6df129d5e1c21ca37f.gif1编程语言 编程语言 (programming language),是用来定义计算机程序的形式语言。它是一种被标准化的交流技巧,用来向计算机发出指令。 Java作为一种 高级编程语言 ,和其他高级编程语言一样,是一种功能强大和多用途的编程语言,可用于开发运行在移动设备、台式计算机以及服务器的软件。
  • 低级编程语言(Low-level programming language)

    接近硬件,机器相关,由0、1串组成,往往不可移植,难于阅读和对人不友好(human-friendly)。

    比如你能看出下面的代码是啥么?

    0000100100101110011001100110100101101100011001010000100100100010011011000110010101100011011101000111010101110010011001010011000100101110011000110010001000001010011001110110001101100011001100100101111101100011011011110110110101110000011010010110110001100101011001000010111000111010000010100010111001110011011001010110001101110100011010010110111101101110000010010010001000101110011101000110010101111000011101000010001000001010000010010010111001100001011011000110100101100111011011100010000000110100000010100000100100101110011001110110110001101111011000100110000101101100001000000110110101100001011010010110111000001010000010010010111001110100011110010111000001100101000010010010000001101101011000010110100101101110...
  • 汇编语言(Assembly language)

    汇编语言使用助记符代替一些机器指令,用地址符号或标号代替指令操作数的地址。开始变得对人友好,可阅读性和便捷性比起机器语言有所提高。但汇编语言只是将机器语言做了简单编译,并没有从本质上解决机器语言的特定性,还是和机器自身和编程环境相关。

  • 高级编程语言(High-level programming language)

    接近自然语言和数学公式,具有更强的表达能力,易于学习和掌握,易于移植。

    • Fortran:第一个科学计算语言

    • Cobol:第一个商业数据处理语言

    • Lisp:第一个函数式程序语言


ea21ce822a490c6df129d5e1c21ca37f.gif2程序基本运行过程 用高级语言编写的程序成为源程序(source program)或者源代码(source code)。由于计算机不能直接运行源程序,源程序必须被翻译为可执行的机器代码。翻译可由 解释器 (interpreter)或者 编译器 (compiler)来完成。由解释器解释的语言叫做 解释型语言 ,由编译器编译的语言叫做 编译型语言编译器 把源代码转化成目标代码,再执行目标代码从而运行程序。 解释器 不生成目标代码,直接执行指令从而运行代码。 87e991ba0cf130918988360776257f2a.png (编译器) f1cdbfc377ad6390c63a4dab7135def4.png (解释器)
编译器和解释器的不同
  • 编译器将源代码翻译成可以直接运行在目标机器上的机器代码;解释器不需要先翻译成机器代码,直接执行源代码中的每一条指令。

  • 编译器花更多时间分析代码关系从而优化代码;解释器只是简单的转化每一条指令然后执行。

  • 解释器直接执行程序直到遇到第一个可以中断执行的错误;编译器保证代码只有完全通过编译才能执行。

Java程序执行过程
Java是一个奇怪的语言,你可以说他是编译型语言,也可以说他是解释型语言。但在我看来,说的准确一点,Java是一个编译型与解释型混合语言。以下为Java程序的执行过程: 702d5550b3a8c908c7f88cc8eb211b26.png (java编译的过程) Java源程序首先经过 Java编译器 生成后缀为.class的Java字节码文件,然后送到JVM执行。JVM首先会使用一个叫做 类加载器 (class loader)的程序将类的字节码加载到内存中。如果程序使用到了其他类,类加载程序会在需要他们之前动态的加载它们。当加载完成后,JVM使用一个称为 字节码验证器 (bytecode verifier)的程序来检验字节码的合法性,确保字节码不会违反Java安全规范。Java强制执行严格的安全规范,以确保来自网络的Java程序不会篡改和危害你的计算机。之后即可通过解释器执行Java程序。Java程序最初是通过 解释器 进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“ 热点代码 ”。为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为 即时编译器 (Just In Time Compiler,JIT)。Java虚拟机规范并没有规定Java虚拟机内必须要有即时编译器存在,但是由于解释器的性能较低,主流的Java虚拟机都采用了 编译器解释器 并存的架构。 从Java执行过程来看,把Java叫做 编译型与解释型混合语言 更准确一点。
常见的编译型语言:C、C++、Pascal、Go等
常见的解释型语言:JavaScript、Perl、Python、Ruby等

ea21ce822a490c6df129d5e1c21ca37f.gif3一般编译器构造 一般编译器按照逻辑可划分为7个部分,词法分析器(lexical analyzer)、语法分析器(syntax analyzer)、语义分析器(semantic analyzer)、中间代码生成器(intermediate code generator)、机器无关代码优化器(machine-independent code optimizer)、代码生成器(code generator)和机器相关代码优化器(machine-dependent code optimizer)。 1e7f75c071974be3e5a321caba1dadd8.png (编译构造) 其中,词法分析器、语法分析器、语义分析器和中间代码生成器4部分叫做编译器前端,编译器前端对源程序进行分析,把源程序切分成一些基本块并生成中间语言表示IR(intermediate representation),并且收集源程序信息存到符号表(symbol table)。 a6fa180620415d55d319ecbc5200ec97.png (前端) 后端负责从由前端传递过来的中间代码和符号表生成目标程序,并且在处理过程中执行代码优化。 a1b9eac8daa8b1d11cca245adf4fab5a.png (后端)
Lexical Analysis(scanning,词法分析)
1d9e2c7bc401b28b9a982d823b35d8cd.png (词法分析) 词法分析器将源代码分成一个一个的词素(lexemes)或者词(words),对R于每一个词素,产生一个词法单元(token)。词素(lexeme),是一个字符串,程序设计语言中的语法单元。词法单元(token),是词素的一个语法集合。比如在英语中的名词、动词、形容词;编程语言中的标识符(identifier),关键字(keyword)等。一个基本的token形式: 如: 60cc612a66e1f43228015d17ee90aa18.png (语法分析)
Syntax Analysis(parsing,语法分析)
56fcff48fd162cad82175e59af2af6b1.png(语法分析器) 词法分析器使用语法分析器生成的 tokens 表示语法结构,这个结构通常是一个语法树(syntax tree)。语法树的中间节点表示操作(operation),孩子节点表示操作的参数(arguments)。 如: e44879cd3b5b5337fb36d65d22fb1924.png (词法分析实例)
Semantic Analysis (语义分析)
f800204db10b70896f249722851cec45.png (语义分析 ) 语义分析器使用语法树和符号表中的信息检查语言定义的语义一致性,同时为类型检查、类型转化和中间代码生成收集类型信息。
  • 语法(syntax)描述程序的适当形式。

  • 语义(semantic)描述程序的意思。

比如在英语中: Jack said Jerry left his assignment at home.(Jack说Jerry把他的作业放过家里了) 这句话是符合语法的,但是我们无法知道这里的“his”指代的是Jack还是Jerry,这就造成了语义不明。语义分析就是为了确定每一条指令的具体意思。
Intermediate Code Generation (中间代码生成)
78683a96fb7a0d69fd92cca2d6a724b0.png (中间代码生成) 当完成语义分析后,编译器生成一个中间表示,通常是三地址码(three-address code)。一张图说明生成中间表示的重要意义。 fc826a488090ffb73e80c0fdf9319737.png (中间表示) 如果没有合适的中间表示,在有 M 种语言和 N 种机器的情况下,就需要 M*N 个不同的编译器。但是存在一个合适的中间表示的情况下,就只需要 M+N 个不同的编译器。大家都知道O(n)和O(n 2 )的区别吧。
三地址码(TAC)
最多只有一个运算符在指令右边,通常形式为 x = y op z。因为涉及三个变量,因此被称为三地址码。三地址码可以有不同的表现形式,典型的表现形式为四元式(Quadruples)、三元式(Triples)和间接三元式(Indirect triples)。
  • 四元式表示法一般形式:<op arg1 arg2 result>

  • 三元式表示一般形式:<op arg1 arg2>

如赋值语句 a = b ∗ −c + b ∗ −c ,以下为对应的三元式和四元式表示。 5ff56ce3b471dd6e595282ea36a70310.png (三元式和四元式) 感觉三元式似乎比四元式简单,但其实三元式存在着一个缺点,无法交换指令顺序从而执行后序代码优化。例如: fde59fb3f00596264304a1efa215ab49.png (三元式缺点) 交换指令1和2并不会影响四元式的执行结果,但是在三元式中,得到了错误的答案。
  • 间接三元式相对三元式增加了一个指令列表,可以实现指令交换。

2d1bdc542c4b32c28fa13e1c9c070c80.png (间接三元式1) 执行交换时: 594b2a1b0447a7ec5177f6521f2be7a2.png (简介三元式2)
Machine-Independent Code Optimization (机器无关的代码优化)
dd2640ea8fcd76304796da04655d4905.png (机器无关代码优化) 机器无关代码优化提高中间代码的质量,目的是为了让它运行的更快,占用更少的内存,代码更短,消耗更少的资源等等。常见的优化点有死代码消除,局部/全局子表达式消除,复制传播和代码移动等。 例如: c6819fe03fb115cd6aefe17eb09da9ab.png (机器无关代码优化例子)
Code Generation (代码生成)
d930a65032d46c4f3020fd3c9d1bc94c.png (代码生成) 代码生成器负责把中间表示(IR)翻译成对应目标机器代码,这里需要处理给变量分配寄存器和内存。 例如: 7e79b280de049217a55d9f755538a395.png (代码生成例子)
Machine-dependent Code Optimization (机器相关的代码优化)
f33a6568996c546c4a7c519080862175.png (机器相关代码优化实例) 机器相关的代码优化是在目标代码生成之后根据目标机器架构转换代码。它涉及CPU寄存器,可能有绝对内存引用而不是相对引用。机器相关的代码优化努力最大限度地利用内存层次结构。 比如某CPU架构将执行一条指令分为5部分
  • IF: 获取指令(Instruction fetch from memory)

  • ID: 指令解码和寄存器读(Instruction decode & register read)

  • EX: 指令执行(Execute operation or calculate address)

  • MEM: 内存访问(Access memory operand)

  • WB: 结果写回寄存器(Write result back to register)

现有指令: add $s0 , $ t0, $ t1 sub $ t2, $s0 , $ t3 如果要顺序执行这两条指令,将会带来两个时钟周期的浪费,因为第二条指令的 s0 依赖于第一条指令的计算结果,需要等待第一条指令写回寄存器后才能计算。 8d7580bbe3de8d765b1f88bbaba139b6.png (机器相关代码优化) 这时可以调换指令执行顺序,将一些执行顺序无关的指令在这两个空时钟周期执行。(其实这里也可以通过一个叫Forwarding/Bypassing的技术解决,这里主要想突出根据CPU结构优化代码)。                                         5d07c17abcef041616d1bd936d857ba5.png
    原创不易,希望大家多多支持>3< 7c02f1aa6fa0642006c800a9b64aa773.png c256344e594bc531534107fa91550070.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值