程序是如何在计算机上被执行的?(上篇:软件部分)

我们用两篇文章说明“程序是如何在计算机上被执行的?”,本文是第一部分,着重说明软件部分——从程序到机器语言,下一篇文章说明硬件部分,即机器语言到逻辑门

本文又拆分成三个部分,分别是:

  • 写在前面,关于思考认知
  • 程序到汇编语言解析
  • 汇编语言到机器语言解析

写在前面

作为前端程序员,最开始在html,css,js中间打转。

后来,应用react、vue等框架,以及前端工程化,性能优化。我发现做的工作较重复围绕在应用层,最近思考了很多,发现框架,语言,其实都是工具,为产品服务,产品为使用者服务,去解决现实中的问题。

于是我从图灵机,冯诺伊曼结构,计算机系统……一个个体系来梳理。本文着重介绍我们写的程序,经历了哪些过程,最终如何跑在计算机核心硬件上被执行的。

流程如下:

程序 => 高级编程语言 => 汇编语言 => 机器指令 => 逻辑门 => 晶体管

整个流程,是从下往上的抽象,是为了让系统方便和易用

从这个角度看,语言,框架,都是工具,类似钳子,起子,不同的语言,不同的框架,针对不同场景,着重解决特定问题。

从程序到机器语言

下面,我用一个c语言实例来说明以上整个解析过程。

i=1,sum=0,count=100; 
//计数器设为100,累加计算结果设为0
while(count-->0){ 
//计数器大于0时,计数器减1并循环执行{}中内容
sum=sum+i;
//每次将sum和i值相加,结果存在sum中;
i++;
//i的值增加1
}

为了在机器上实现以上c语言编写的程序,我们需要能够实现语言之间转换的编译器。编译器,指能将一种语言翻译成另一种目标语言的程序。在上述程序中,我们需要实现两个编译器:

  1. 高级语言编译成汇编语言
  2. 汇编语言编译成机器语言

1、高级语言编译成汇编语言

此过程较为复杂,首先会对原语言进行多次扫描,经过中间代码生成和代码优化,最终生成目标代码。

用伪代码解释一下这个过程:

P(原代码){
循环(扫描原代码片段,扫描完停止){
 词法分析;
 语法分析;
 语义分析;
 目标代码
}
}

汇编语言目标代码= P(高级语言原代码)

下面分别说明:

  • 词法分析
  • 语法分析
  • 语义分析
  • 目标代码

词法分析

词法分析,主要是把源代码里面所有字符串读进来,然后进行扫描和分解,把常量、变量名、运算符、关键字等标识出来。例如对于上达例子中的语句i=1,sum=O,count=100需要将其正确地识别成如下的序列 i=1sum=0count=100而不会犯把 100识别成1 0 0三个字符这样的错误。

js中建立词法环境和变量环境也是在这个阶段。

语法分析

此阶段主要是在词法分析的基础上将识别出来的单词序列按照该语言的语法要素识别出相应的语法单位。如上句中一共有三个表达式,而且表达式本身可以嵌套递归,如count--是表达式,count-->0同样是表达式。

语义分析语义分析主要作用是判断整个源程序代码里面是否有错误,如变量是否已经声明,语句是否以分号结束,运算对象是否合理等进行审查。

每一种语言都有其规则,根据规则进行检查。

目标代码生成将源代码转换成目标代码是最重要也最复杂的阶段。如上例所示,

  • i=1;sum=0,count=100语句中三个赋值表达式转换成3条Mov汇编指令,存在三个寄存器中,
  • 然后把while语句的范围转换成loop和end之间的代码,
  • sum=sum+i转换成 add A,R1
  • i++转换成inc R1
  • count--转换成 dec RO
  • while(count-->0)转换成jgz RO,Loop

js上下文解析,确定作用域链,确定this指针在这一阶段。

通过以上过程,就把这段c语言生成了汇编语言代码。

2、汇编语言编译成机器语言

从汇编语言转换成机器指令基本过程也差不多,而且这个过程比将高级语言转换成汇编语言要简单。因为在设计cpu的时候,人们对于相应操作以及给出了相应的操作码(工具,封装,易用)。

例如上述举的 Intel 8080 芯片的例子,其 mov操作就是最终生成的机器指令:从40到5F 的一系列数字。因此机器语言完全就是数字的序列。这样就完成了从高级语言到计算机能够运行的代码的过程。

其实对于编程语言来说,语言的关键字符、书写形式等构成的是语言的语法,但语言的强大与否并不在于语法,而在于提供的相应操作函数的数量,一般语言提供的大量相关的数称为“类库”。(工具性)

在实现自已的编程语言时,除了需要实现语言的编译器以外,更至的是需要提供强大的、适用的函数类库。

例如前面的语言,如果提供一个叫sum 的累积求和函数,只需要一行语句 sum(1,100)就可以实现从 1加到 100 的加法计算功能。

由于不同的语言设计目的不同,函数库侧重不同,因此不同的语言适用于不同的功能。

如进行快速 Windows窗口开发,C#或者 Visual Basic.NET 更适合;web开发用html,css,js;服务端用Java 和 Python(由于其开源的特性,有大量的第三方类库能够支持特定的功能)。

这也就是我前面说的,所有的语言都是等价的,任何语言都可以通过编译器实现从一种语言到另一种语言的转换

以上说明了程序是如何在计算机上被解析成机器语言的,以及对语言框架新的认知。

总结一下:计算机所做的工作是由程序规定的。程序是由编程语言编写的。编程语言是由解释程序或编译程序,通过预定义子程序集,即操作系统,转化为机器语言指令序列的。这些指令存储在计算机的存储器中。有限状态机取出并执行这些指令。指令和数据都是用二进制位组来表示的。有限状态机和存储器都是由寄存器和布尔逻辑块来构造的。布尔逻辑块建立在与、或、非这些简单逻辑功能的基础上。这些逻辑功能又是通过开关来实现的。

下一篇文章会着重讲后一部分,即机器语言如何在计算机硬件上运行,关于逻辑门,加法器,布尔运算,感谢您的阅读。

posted @ 2022-04-13 22:11  优前程  阅读(427)  评论(0编辑  收藏  举报