编译原理-程序设计语言的设计

本文深入探讨了程序设计语言的设计,涵盖了编译程序结构、变量属性、虚拟机、类型系统和控制结构等多个方面。讨论了变量的静态与动态绑定,以及类型的作用、分类和等价性。此外,还介绍了编译过程,包括词法分析、语法分析、语义分析,并提及了虚拟机的概念。文章最后涉及到了程序设计语言的控制结构,如选择、重复和并发,以及子程序调用中的副作用和别名问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

机器语言:二进制、机器相关
汇编语言:助记符、机器相关(机器语言与汇编语言都是低级语言)
高级语言:接近自然语言、机器无关
 

把一种语言程序编写的转换成完全等效的另一种语言编写的程序为翻译

编译程序: 源程序语言是高级语言,目标程序语言是汇编语言或机器语言之类的低级语言,这样的翻译程序称为编译程序

翻译汇编语言的程序称为汇编程序

翻译高级语言的程序称为编译程序。所以编译程序是一种翻译程序。

编译程序与解释程序:

(1)编译程序会产生目标程序;而解释程序不产生目标程序; (2)编译程序实现起来比较复杂;而解释程序本身实现起来比较简单; (3)编译程序效率比较高;而解释程序运行效率比较低,需对语法、词法、语义等进行检测;可移植性高。

变量 存储单元及它的名称由变量的概念来代替;
     可以代表一个或一组单元,可以修改。

编译程序结构

词法分析、语法分析、语义分析与中间代码生成、代码优化、目标代码生成

其中(中间代码生成和代码优化不是每个编译程序必须的)

​​​​​​​

绑定

绑定:一个实体(或对象)与其某种属性建立起某种联系的 过程,称为绑定。
静态绑定:凡是在编译时能确定的属性,称为静态属性;
      若绑定在编译时完成,运行时不改变,称为静态绑定。
动态绑定:凡是在运行时才能确定的属性称为动态的。
          若绑定在运行时完成,称为动态绑定。
 

变量及其属性

变量是对一个(或若干个)存储单元的抽象,赋值语句则是修改存储单元内容的抽象

变量除名字外,具有四个属性:作用域、生存期、值和类型。

变量的作用域:可以访问该变量的程序范围。

静态作用域绑定:按照程序的语法结构定义变量的作用域。
动态作用域绑定:按照程序的执行动态地定义变量的作用域。

变量的生存期:

一个存储区绑定于一个变量的时间区间,称为变量的生存期。

变量的值:即变量对应存储区单元的内容,变量与它的值的绑定是动态的

    变量的初始化,几种处理方法:
        不初始化则出错
        随机
        缺省值0

变量的类型

类型的定义:    变量的类型是与变量相关联的值的类,以及对这些值进行的操作的说明。

静态绑定:通过说明语句完成 如:Pascal、Fortran、C

动态绑定:执行时隐式说明,且动态变化

         
虚拟机

虚拟机是由软件实现的机器。

翻译汇编语言的程序称为汇编程序(器)

翻译高级语言的程序称为编译程序(器)

机器语言就是二进制。汇编语言类似三元式

高级语言:

直观、自然、易于理解

易读、易写、易于交流、出版和存档

一般都是独立于机器的,易于移植

程序单元

程序单元:程序执行过程中的独立调用单元; 如子程序、分程序、过程等。

在编译时,单元表示是该单元的源程序。

运行时,单元表示由一个代码段和一个活动记录组成,称为单元实例
活动记录:执行单元所需要的信息,以及该单元的局部变量所绑定的数据对象的存储区。

引用环境:局部变量+非局部变量

别名:同一单元的引用环境中有两个变量绑定于同一数据对象,称这些变量具有别名。

副作用:对绑定于一个非局部变量的对象进行修改时,将产生副作用。

程序单元可以递归激活,从而一个单元可以有很多个实例,但代码段相同。不同的仅仅是活动记录。

数据类型  

数据类型实质上是对存储器中所存储的数据进行抽象。 它包含一组值的集合和一组对这组值的操作的集合


数据类型的作用

实现了数据抽象
使程序员从机器的具体特征中解脱出来
提高了编程效率

数据类型的分类

内部类型:语言定义的
自定义类型:用户定义的

内部类型的优越性

内部类型是对硬件基本位串的抽象。

1.基本表示的不可见性:基本位串对程序员是不可见的。
优点(程序员): 导致不同的程序设计风格、可写性、可读性、可修改性

2.编译时能检查变量使用的正确性,进行静态类型检查

3.编译时可以确定无二义的操作

超载(多态)的概念:运算符的意义依赖于操作数的类型。如“+”可以表示整数加或实数加

编译时,可拒绝混合运算,或提供类型转换指令
4.精度控制:可以通过数据类型显式定义数据的精度

用户定义类型(6种聚合方式)

用户自定义类型是对内部类型和其他用户自定义类型的抽象。

1. 笛卡尔积

C语言:结构Struct

struct student {
       int num;
       char name[2];
       char sex;
       int age;
       float score;
       char addr[30];
    }


Pascal语言: 记录类型,构造符RECORD用以定义笛卡尔积

记录可以整体访问,也可用圆点“.”作为选择符访问单个的域;

语言把笛卡尔积数据对象看成由若干个域组成,每个域有一个唯一的名字;通常用域名来选取域,对它进行修改

2.有限映像

从定义域类型DT(domain type)的值的有限集合,到值域类型RT(range type)的值的有限集合的函数称为有限映像(射) 。

数组

值域对象通过下标选取
 下标越界会出错,动态检查
 下标可用来选取值域的多个元素,如:a[3..10]
  SNOBOL4的ARRAY构造符并不要求值域集的所有元素是同一类型的

内情向量

把数组的有关信息记录在一个“内情向量”中,每个数组的内情向量必须包括:维数,各维的上、下限,首地址,以及数组(元素)的类型

3.序列

序列由任意多个数据项组成,这些数据项称为该序列的成分,且类型相同(记为CT)

是从所周知的序列,其成分类型为字符;顺序文件的思路也来自序列的概念

PASCAL文件是任意类型的诸元素的序列

4.递归

若数据类型T包含属于同一类型T的成份,那么类型T称为递归类型。

允许在类型定义中使用被定义类型的名字
指针是建立递归数据对象的重要手段

典型:二叉树

5.判定或

判定或是一个选择对象结构的构造机制,规定在两个不同选择对象之间作出适当的选择; 每一选择对象结构称为变体。

例如:PASCAL中的变体记录; 

type dept=(house,sports,drugs,food,liquor);
     month=1..12;
     item=record
            price:real;
            case available:boolean of记录的判定成分
                 true:(amount:integer; where:dept);
                 false:(month_expected:month)
          end;

C中的联合:

C语言中构造符union(联合)支持判定或


6.幂集

类型T的元素所有子集的集合,称为幂集,记为Powerset(T),T称为基类型。

由于具有该类型的变量的值是一个子集,因此它们的基本操作是集合的操作,比如:联合、与、以及测试某个元素是否在一个集合中等。

PASCAL语言的SET构造符是幂集构造受限制的形式,基类型只能是有序类型,而不能是实数、集合类型。

与类型相关的三个操作

类型检查

对数据对象的类型和使用的操作是否匹配的一致性检查称为类型检查
语言的类型检查分为静态检查(static checking)和动态检查(dynamic checking);
静态检查(在编译时进行)使程序更正确更有效
动态检查(在运行时完成)使编程方便,但影响了可读性,且降低了执行效率
语言按类型可分为强类型语言和弱类型语言、无类型语言

无类型语言:没有类型定义

强类型语言:所有类型检查都可以在编译时完成。

弱类型语言:检查全部或部分要在运行时完成(动态检查)

PASCAL是非强类型语言
理由:
编译时,不能确定一个过程中的过程参数和子程序参数类型
Pascal的子界类型不能静态检查
变体记录的标识符可以在运行时改变
Pascal没有严格规定类型的一致性规则

类型转换

将一个类型的值转换成另一个类型的值,称为类型转换;
类型转换分为拓展(widening)和收缩(narrowing)

              拓展:整型-》实型
             收缩:实型-〉整型

1.截断
2.舍入法


类型等价

若T1和T2是两个类型,且T1的任何值都可以赋予T2类型的变量,T1类型的实参可以对应类型T2的形参,反之亦然,则称T1和T2是相容的,或等价的;
有两种类型的等价概念:
①名字等价     两个变量的类型名一样
②结构等价     两个变量的类型具有相同的结构 
两种等价实现时的比较
    ①名字等价的实现比较简单
    ②结构等价的实现需要的模式匹配过程可能十分复杂

类型抽象

内部类型隐蔽了基本表示,不能对它的成分进行操作;用户定义类型具有更高级别的抽象,可以对其基本表示的成分进行操作。

仿照内部类型,隐藏用户自定义类型的内部信息---》抽象数据类型

满足下述特性的用户定义类型称为抽象数据类型:

在允许实现这个新类型的程序单元中,建立与表示有关的具体操作。

对使用这个新类型的程序单元来说,新类型的表示是隐蔽的。

​​​​​​​

抽象数据类型

1. SIMULA 67的类机制
2. CLU的抽象数据类型-簇

3. Ada的抽象数据类型

4. Modula-2的抽象数据类型

C++中的类
 


控制结构

控制结构:程序员用来规定程序各个成分的执行流程的控制部分

语句级控制结构和单元级控制结构。

语句级控制结构

语言用来构造各种语句执行顺序的机制

顺序(sequencing)

顺序运算符;
语句括号begin . . . end 

选择(selection)

1.if语句

一般形式:
    if 条件 then 语句1 else 语句2
选择结构引起二义性
    if x>0 then if x<10 then x:=0 else x:=1000

ALGOL 60加入begin..end来消除二义性:
if x>0 then begin if x<10 then x:=0 else x:=1000 end
if x>0 then begin if x<10 then x:=0 end else x:=1000

2.多重选择

PL/1的select结构
   SELECT:
      WHEN(A)S1;
      WHEN(B)S2;
      WHEN(C)S3;
      OTHERWISE S4;
  END
多种语言的case语句
Java中Switch语句的选择结构
switch  (表达式)
      {
            case   常量表达式1 :语句1;
            case   常量表达式2 :语句2;
            …….
            case   常量表达式n :  语句n;
            default : 语句n+1;
      }
一旦碰到第一次case匹配,就会开始顺序执行以后所有的程序代码,而不管后面的case条件是否匹配,后面case条件下的语句都会被执行,直到碰到break语句为止。

3. Dijkstra选择结构

if B1→S1
 B2 →S2
 B3 →S3
   …...
 BN →SN
其中,Bi是布尔表达式,称为卫哨。
若有多个卫哨为真时执行任意Si。
特性:非确定性


重复(repetition)

1. 计数器制导

当预先知道重复次数时,在循环计数器值的有限集合上重复。
 ① FORTRAN的DO循环中,用标号控制循环体
         DO 7 I=1,10
         A(I)=0
         B(I)=0
         7  CONTINUE实现下标从1到10置0.

② Pascal的for 语句

计数重复的值可在任何有序集上
for . . . to递增
for . . . downto递减

for (表达式一;表达式二;表达式三) 
   {
          执行语句;
   }
表达式一:初始化表达式;
表达式二:循环条件表达式;
表达式三:循环后的操作表达式。


for (int i=0; i<10; i++)
{
      System.out.println(i);
}
int i=0;初始化
for (; ; )
{
      if (i >= 10) 
                 break;条件表达式

      System.out.println(i);
     操作表达式
}


2.条件制导

① while 循环:描述0或任意多次的重复

while  (条件表达式语句)
      {
          执行语句
      }

while 表达式的括号后面一定不能加“;” 
② repeat until循环:至少一次以上的重复

Dijkstra的卫哨命令表示法
       do B1→S1
         B2→S2
          . . . . . .
         BN→SN
      od

重复执行直到没有Bi为真。若有多个Bi为真,任选一个Si执行。

顺序是按计算机程序计数器提供的顺序获得指令的一种抽象;
     选择和重复是对硬件显式修改程序计数器的值实现无条件和条件转移的抽象;
goto是任意修改程序计数器的抽象;但无限制地使用goto语句会使程序晦涩难懂,容易出错;

若不使用goto,语言又缺乏专门的控制结构,编写的程序也会不符合语言习惯而难懂。

虽然各种语言提供了多种多样的控制结构,但没有一种控制结构是令人满意的。

单元级控制结构

规定程序单元之间控制流程的机制
四种:
显式调用
异常处理,隐式调用单元

协同程序
并发单元


一.显式调用从属单元

由调用语句使用被调用单元的名字来进行调用。

参数的两种绑定方式:位置绑定、 关键字绑定

subprogram S(F1,F2,…,FN);
        ……
end
位置绑定: call S(A1,A2,…,AN)
        call S(A1,,A3,,,,,A8,,A10)对应位置的就是参数
关键字绑定:
        call S(A1=>F1,A3=>F3,A8=>F8,A10=>F10)这个时候位置顺序不重要

子程序调用中副作用和别名会影响程序的可读性,引发程序出错。

副作用

对非局部环境的修改

x、y为变参
z为全局变量

  ①副作用降低了程序的可读性
  ②副作用限制了数学运算律的使用
        如:w:=x+f(x,y)+z

由于f(x,y),如果存在副作用,对非局部变量进行了更改,那么主函数中x+f(x,y)和f(x,y)+x的计算结果是不相同的。降低了程序的可读性,使表达式不遵守交换律。
  ③副作用影响目标代码的优化
        如:u:=x+z+f(x,y)+f(x,y)+x+z
考虑到f(x,y)的副作用,就不能提取公因子,只计算一次x+z,因为后面的x+z可能受到影响和前面的计算结果不一致。

别名

在单元激活期间,两个变量表示(共享)同一数据对象对非局部环境的修改。

FORTRAN的EQUIVALENCE语句,  EQUIVALENCE(A,B)

② Pascal的变参使得形参和实参共享同一数据对象
变参和全局变量表示同一数据对象时,也会引起别名

procedure swap(var x:integer); /*a是全局变量*/
begin
         x:=x+a;
         a:=x-a;
         x:=x-a;
end;
调用
swap(a);      将产生不正确的结果

别名也影响编译器生成优化的代码

a:=(x-y*z)+w    /* 若a与x、y或z中任   
             b:=(x-y*z)+u       一个是别名  */
           
⑤别名的消除
         .废除可能引起别名的结构
         .限制使用指针、变参、全局变量、数组等

异常处理

异常是指导致程序正常执行中止的事件,要靠发信号来引发,用异常条件来表示,并发出相应的信号,引发相应的程序。
隐式地将控制从一个单元转向到另一个单元,通常用于异常处理

SIMULA 67语言协同程序

两个或两个以上程序单元之间交错地执行,这样的程序称为协同程序。

并发

诸程序单元并行活动

程序设计语言

程序设计语言是用来描述计算机所执行的算法的形式表示;
语言=语法+语义
语法:用以构造程序及其成分的一组规则的集合
语义:用以规定语法正确的程序或其成分的含义的一组规则的集合

词法规则:规定什么样的字符串可以构成语言的有效符号

语法规则:确定一个符号序列是否为一个句子,并提供句子的结构(什么样的符号序列是合法的)
 

生成的观点:产生式

① 一个简单英语句子的描述
     I/Students Study/Run

<语句>→<主语><谓语>----每行称为一条语法规则
<主语>→I|Students         终结符、非终结符
<谓语>→Study|Run

② 文法
在形式语言中,上述例子可写成文法
G=(N,T,P,S)

N={<语句>,<主语>,<谓语>}非终结符
T={I,students,study,run}终结符
P={<语句>→<主语><谓语>,
      <主语>→I|Students,
      <谓语>→Study|Run}产生式
S=<语句>开始符

③ 语言:所有句子的集合
④ 标识符和表达式描述

标识符:字母开头的,由字母和数字组成的

<标识符>→<字母>

 <标识符>→<标识符><字母>

 <标识符>→<标识符><数字>

 <字母>→A|…|Z|a|…|z

 <数字>→0|…|9

表达式
<表达式>→<标识符>
<表达式>→(<表达式>)
<表达式>→<表达式><运算符><表达式>
<运算符>→+|-|*|/


识别的观点:语法图

② 识别原则

若一个终结符序列是合法的,那么,必须从语法图的入口边通过语法图而到达出口边,而且在通过的过程中,恰恰能识别该终结符序列。具体如下:
终结符框:标识的终结符与被识别的终结符刚好符合

非终结符框:由该非终结符的语法图来识别;

分支:若遇到分支,则任选一分支来识别;

回溯:若一个分支识别不成功,则选另一分支来识

③ 语言:语法图能识别的所有终结符序列的集合


语义:

1.何谓语义:定义语言合法句子的含义,即句子的作用和意义。

2.语义的描述:

GAM(虚拟机)

指令指针+代码存储器C +数据存储器D

文法

文法G定义成一个四元式:
    G=(VT,VN,S,P)
其中
VT是终结符的有限集合;Terminal
VN是非终结符的有限集合;
S  属于VN是开始符号;
P是产生式的非空有限集
约定:用英文大写字母表示非终结符;小写字母表示终结符;希腊小写字母表示串

文法的分类

0型,alpha中一定有一个非终结符就行!

1型,左边长度小于等于右边长度。或者又名上下文有关文法。替换时会收到前后的影响。

2型:左边仅有一个非终结符。所以不受上下文限制,又名上下文无关文法。

3型:左边仅有一个非终结符,右边只有一个终结符和一个非终结符。非终结符在右边称作正则文法、右线性文法。

非终结符在左边称为左线性。左线性文法。

文法语言的产生

1.推导与规约

举例: 已知G(E): E→E+E│E*E│(E)│i,求 i+i*i的推导过程

最右推导是每次被换的都是最右边的非终究符。规范推导

最左推导是先换左边为终结符。

2.句型和句子

由文法推导出来的任意符号串都是句型,包括开始符本身。

仅由终结符组成的句型是句子。

3.文法产生的语言

句子的全体,即所有可能推导出来的结果。

①文法的重要特性:用有限规则描述无穷语言

②文法的等价:两个文法G和G’,如果有产生的语言相同 L(G)=L(G’),则称G和G’等价

4.短语、句柄

有多少个非叶子节点(分枝节点),就有多少个短语。任何子树的边缘是子树根的短语。

只有一代的子树的边缘就是该子树的直接短语。

句柄:最左直接短语,最左左边的子树。

素短语:含有终结符的短语,并且它的真子串不具有这个特性。


  最右推导(规范)、最左推导

5.语法树(推导树)

以图的方式表示推导过程
①推导树是一棵有序的标记树

  每个结点的标记是文法G的非终结符或终结符;
  标记为A的内部结点从左到右有子结点X1,X2,…, Xn,    则A→X1…Xn是一个产生式;
推导树的边缘:一棵推导树所有叶结点的从左到右的连接。
④文法的二义性:一个句子有两棵不同的推导树。
由推导树确定短语(根据子树)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐果然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值