PL真有意思(一):引言
前言
断断续续学编译原理到之前发过写一个编译器和正则表达式引擎系列文章也有一段时间了,然后最近看完PLP这本书,这本书应该算是入门书,但是对我这种半吊子收获很大。所以为了弥补最近学操作系统和接外包摸的鱼,就想写写看完这本书的收获。(为拙劣的标题道歉
程序设计语言的谱系
现在的新语言都是一撮一撮的出来,但是基本都可以用他们的计算模型来分成两类,一类是更关心计算机做什么的说明式,一类是更关心计算机怎么做的命令式
一般认为像函数式逻辑式语言都算是说明式,而冯诺依曼式和面向对象的都被认为是命令式
函数式
函数式是基于函数的递归定义的计算模型,一般从本质上来看,函数式把程序认为是一种从输入到输出的函数,使用更简单的函数通过逐步细化的过程来定义
逻辑式
逻辑式里经典的应该就是Prolog了,逻辑式一般将计算看作是一种找出满足某些特定关系的值的尝试过程
冯诺依曼式
冯诺依曼式最重要的就是通过副作用也就是修改寄存器里的值来对后续计算产生影响,像C和Fortran都属于冯诺依曼式
几个例子
如果C语言来实现求最大公约数,可以发现C语言偏向通过迭代和反复修改变量的值来实现
int gcd(int a, intb) {
while (a != b) {
if (a > b) {
a = a - b;
} else {
b = b - a;
}
}
}
从lisp来看,则更加关注输入和输出的数学关系,要算出最大公约数,需要对函数的不断的扩充和精简
(define gcd
(lambda (a b)
(cond ((= a b) a)
((> a b) (gcd (- a b) b))
(else (gcd (- b a) a)))))
对于像C或者Java入门的人,看到Prolog可能头都大了,因为Prolog和命令式的思考逻辑完全不同,逻辑式更倾向给出一组公理和检测规则,期望系统能给出相应合理的值,我也仅限于能看懂这些小程序
gcd(A,B,G) :- A = B, G = A.
gcd(A,B,G) :- A > B, C is A - B, gcd(C,B,G)
gcd(A,B,G) :- B > A, C is B-A
gcd(C,A,G)
编译和解释
下面再看两个概念,编译和解释。
编译一般是指从一个语言到另一个语言的翻译,无论是高级语言到汇编还是高级语言到高级语言都算是编译。而解释就是直接执行代码,但是现代的解释器,一般还有虚拟机一层,即翻译到虚拟机指令再由虚拟机进行执行
自举
很多语言的编译器都是由自己编译而成的,所以问题就是,最开始的编译器是怎么编译的?
假设现在要为Java编写一个编译器,我们可以先用C语言编写一个Java小子集的编译器,然后再手动将C语言翻译到这个Java子集,就可以由这个子集编译运行自己,然后就可以不断扩充这个编译器
编译概览
其实这个在之前那个写编译器的系列是说得最详细的,这个系列是想要写写笔记对实践和语言设计结合的说。
词法分析
有关词法分析其实就是将字符流化成单词流,记录每个单词的信息,然后通常还会有其它更多的信息让编译器更好的生成错误信息
语法分析
语法分析通常会用到一个概念:上下文无关文法,就是用来定义语法形式的,比如while语句就可以这样表示
while-statment := WHILE ( expr ) statment
一般语法分析过程最后的输出都是树状结构
语义分析和中间代码生成
语法分析只保证源代码语法格式的正确,但是却不能保证其它的正确性,比如对于静态类型的语言,可能就会在编译时直接检测出类型错误
而在语义分析过程一般还需要借助一个叫做符号表的数据结构,这个符号表将每个标识符都映射到关于它的已知信息
中间代码的生成通常是会将树形结构翻译成更接近汇编的中间线性格式,但是中间格式不是必须的,比如之前那个系列里还写了C的解释器,虽然很残缺,它是没有中间代码的,连虚拟机都没有,是直接进行遍历语法树进行执行解释的
代码优化
有些代码改进是机器无关的,即可以在中间格式上就进行优化,但是有的代码优化是平台相关的,所以就需要在最后对目标语言优化
目标代码生成
代码生成阶段就是根据之前生成的线性结构和符号表信息对目标代码的生成
小结
这一篇主要说了几个范式的语言和编译过程的概括,对摸鱼进行忏悔
PL真有意思(一):引言的更多相关文章
- PL真有意思(四):控制流
前言 对大多数计算模型而言,顺序都是基本的东西,它确定了为完成所期望的某种工作,什么事情应该最先做,什么事应该随后做,我们可以将语言规定顺序的机制分为几个类别: 顺序执行 选择 迭代 过程抽象 递归 ...
- PL真有意思(二):程序设计语言语法
前言 虽然标题是程序语言的语法,但是讲的是对词法和语法的解析,其实关于这个前面那个写编译器系列的描述会更清楚,有关语言语法的部分应该是穿插在整个设计当中的,也看语言设计者的心情了 和英语汉语这些自然语 ...
- PL真有意思(三):名字、作用域和约束
前言 这两篇写了词法分析和语法分析,比较偏向实践.这一篇来看一下语言设计里一个比较重要的部分:名字.在大部分语言里,名字就是标识符,如果从抽象层面来看名字就是对更低一级的内存之类的概念的一层抽象.但是 ...
- PL真有意思(五):数据类型
前言 现在大多数程序设计语言中都有表达式和/或对象的类型概念.类型起着两种主要作用: 为许多操作提供了隐含的上下文信息,使程序员可以在许多情况下不必显示的描述这种上下文.比如int类型的两个对象相加就 ...
- PL真有意思(六):子程序和控制抽象
前言 在之前我们把抽象定义为一种过程,程序员可以通过它将一个名字与一段可能很复杂的程序片段关联起来.抽象最大的意义就在于,我们可以从功能和用途的角度来考虑它,而不是实现. 在大多数程序设计语言中,子程 ...
- PL真有意思(七):数据抽象和面向对象
前言 在之前的名字.作用域那篇提到模块类型,它使程序员可以从一个给定抽象出发,通过实例化产生多个实例:再后面是类,它使程序员可以定义一族相关的抽象. 在这一篇里,我们会来看一下面向对象程序设计及其三个 ...
- PL真有意思(八):其它程序设计模型
前言 在之前几篇我们讨论的语法.语义.命名.类型和抽象适用于所有语言.然而我们的注意力都主要集中在命令式语言上,现在这篇来看看其它范式的语言.函数式和逻辑式语言是最主要的非命令式语言. 函数式语言 命 ...
- R统计软件真有意思哈,以后我怕要用得着,先自学
呵呵,作数据分析是数据监控后的动作. 思路是用监控系统产生数据, 如果监控本身提供统计最好,如果不提供,则可以用R来作分析统计和预测. 如果数据不符合规范,则用PYTHON进行处理转换. ~~~~~~ ...
- 悟透JavaScript
要理解JavaScript,你得首先放下对象和类的概念,回到数据和代码的本原.前面说过,编程世界只有数据和代码两种基本元素,而这两种元素又有着纠缠不清的关系.JavaScript就是把数据和代码都简化 ...
随机推荐
- RAW网络编程
LWIP提供了三种的可以被应用程序直接调用的接口API: (1) 低水平的,基于内核/回调函数的API(后面称 RAW API) 适用于数据量不大,没有os的MCU (2) ...
- cmake::编译一个工程
1.编译工程,构建过程产生的临时文件等文件与源码隔离,避免源码被污染. # CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 项目信息 proj ...
- Linux必备工具与软件包
yum -y update(所有都升级和改变) 升级所有包,系统版本和内核,改变软件设置和系统设置 ----------------------------------------------- yu ...
- ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
1. 前言 现在,通常,为了让手机连上一个WiFi热点,基本上都是打开手机设置里面的WiFi设置功能,然后会看到里面有个WiFi热点列表,然后选择你要的连接上. 基本上你只要打开手机连接WiF ...
- 不同的phper该如何区别使用swoole和workerman?
那么我们该怎样去区别应用swoole和workerman? workerman workerman纯php写的,swoole是php的c扩展,性能肯定更高,百度.腾 ...
- Just 5分钟!使用k3s部署轻量Kubernetes集群快速教程
大小仅有40MB的k3s为想要节省开销进行开发和测试的企业提供了一个很好的选择.本文将用一种极为简洁的方式,教你在5分钟之内使用k3s部署轻量Kubernetes集群. Kubernetes已经改变了 ...
- ubuntu19.10桌面版
一:安装ubuntu卡住,英伟达显卡兼容性问题 解决方法: 将 quite splash --- 改为 quite splash nomodeset 二:从零开始配置ubuntu19.10 sudo ...
- 转:如何让phpmyadmin输入密码再进入
对于很多不熟悉PHP环境安装的朋友来说,用集成环境可以更快的上手,更方便的搭建PHP的运行环境,但是,WAMP的集成环境仅仅是将底层基础工作做好了,有些个别关键的配置操作并没有集成到环境安装中,所以给 ...
- Linux基于webRTC的二次开发(一)
最近在做Linux平台下webRTC的二次开发,一路摸索,中间踩了不少坑,这一篇博客先来简单介绍下Linux上如何使用GCC编译webRTC. 为什么使用GCC编译? 这其实是无奈之举,Linux下w ...
- python中str.isdigit()用法
str.isdigit()中只包含数字返回true,包含其它则返回false