猪qiguo的gravatar头像
猪qiguo 2019-01-08 10:12:10
语言设计及其它

    一、与程序设计语言有关的人
    1. 语言的设计者。
    2. 语言的实现者。
    3. 语言的使用者。

    二、历史上有重要影响的程序语言

    1. 汇编语言
    1948年,英国 David Wheeler (惠勒) 为剑桥大学发明的计算机 EDSAC 写了他称之为起始指令的30行指令。这就是汇编语言的开端。

    2. Fortran 语言
    意为 FORmula TRANslation。由 IBM 公司 Backus 领导的团队设计,于 1957 年推出的第一个的高级语言,主要用于科学计算。引入了高级语言的许多概念,如变量、赋值、数组、无条件(goto)语句、条件语句、循环语句、读语句、写语句、子程序等。

    3. ALGOL 语言
    意为 Algorithm Language。由德国和美国的科学家设计,于1960年推出 ALGOL 60。首次用巴科斯-诺尔范式(BNF)描述。引入了程序块 (Block)、递归过程、动态数组等新概念。ALGOL 在欧洲、中国等国家得到了广泛的应用。

    4. COBOL 语言
    由女程序员 Grace Hopper (1906-1992) 博士领导的一个工作委员会,研制出的第一个的商用编程语言。引入了文件、数据描述、变体记录等概念。该语言的语句近似于英语句子。Grace Hopper 为大型数字计算机 Mark-I、Mark-II、Mark-III 写出了大量程序,写出了世界上第一个编译程序 A-0。

    5. LISP 语言
    由麻省理工学院 John McCarchy 于1960年设计和实现的人工智能语言,是第一个的函数式语言。采用统一的数据结构——表(list),程序作为数据的一部分。

    6. Pascal 语言
    由美籍瑞士人 Niklaus Wirth 设计、并于1970年推出的语言。支持记录和指针的动态数据分配(new),支持嵌套(局部)过程和函数。在多达20年的时间里成为大学里广泛使用的教学语言。

    7. C 语言
    美国 Bell 实验室的 Richie 于1973年发明。直至今天,仍广泛用于系统编程、应用编程和教学,生机勃勃。在编程中大量使用指针,既灵活、高效,也是许多难以查出的错误的来源。

    8. Ada 语言
    表现能力很强的通用程序设计语言,它是美国国防部为克服软件开发危机而招标,耗费巨资,历时近20年研制成功。以严谨、高度安全为目标,实现了软件工程学的许多思想。多用于军用软件开发。

    9. C++
    基于 C 语言,引入了面向对象。功能强大,支持泛型,有一个庞大的库。语法晦涩。

    10. Java 语言
    由美国 Sun 公司的 James Gosling 领导的小组设计,于1995年推出。其面向对象的特性,类似于C++语言。也有一个庞大的库。采用垃圾回收、数组下标越界检查,取消了显式的指针,程序安全性高。采用独立于平台的Java虚拟机,目标程序的执行速度比C/C++慢。多用于大型项目开发。

    三、数据类型

    1. 基本类型
C:
    void,
    (unsigned )char, (unsigned )int, (unsigned )long, enum,
    float, double, long double。

Pascal:
    integer, real, char, boolean。

Ada:
    Boolear, Character, Integer, Float。

Java:
    boolean, char, byte, short, int, long, float, double。

    2. 结构类型
C:
   struct {
      char id[20];
      int age;
   } person;

Pascal:
   person: record
      id: array[1..20] of char;
      age: integer;
   end;

Ada:
   type Coordinate is
   record
      x: INTEGER range 0..1023;
      y: CHARACTER;
   end;

    3. 数组
Pascal:
   var a: array[1..50] of char;

C:
   char a[50];

    4. 指针和递归定义

    二叉树的定义:
C:
   typedef Node * Tree;
   struct Node {
      int data;
      Tree left, right;
   };

Pascal:
   type
      Tree = ^Node;
      Node = record
         data: int;
         left, right: Tree;
      end;

Ada:
   type Node;
   type Tree is access Node;
   type Node is
      record
         data: INTEGER;
         left, right: Tree;
      end;

    5. 枚举和集合

Pascal:
   type Color = (red, green, blue, black, white);
   var  set of Color;

C:
   typedef enum {red, green, blue, black, white} Color;

Ada:
   type BOOLEAN is (FALSE, TRUE);

    6. 子界

Ada:
   type Score is range 0..100;

Pascal:
   type Score = 0..100;

C:
   无。

    四、类型检测

    1. 类型的兼容性 (compatible) 检测

    表达式中的运算对象,赋值中右边和左边,函数调用中实参和形参,编译时要检查类型是否兼容。

    如在 C 中,
int    a  = 100, x;
double b  = 0.618;
char   c  = 'A';
char * st = "Hello.";

x = a + b + c;    // 合法
a + st        // 不合法

但在 JavaScript 中,数和字符串相加是合法的。

    类型检测是语言可靠性中的一个重要因素。编译时的类型检测要比运行时的类型检测更为理想,因为运行时的类型检测代价很高。程序中的错误发现得越早,改正错误的代价就越低。

    现代语言还具有及时改正运行时错误,即异常处理的能力。

    2. 类型等价

    有两类等价:

    1) 名字等价:具有相同的类型名者,为等价。

    2) 结构等价:具有相同的结构者,为等价。
    
    C 语言规定: 1) struct 和 union 采用名字等价。2) 数组和指针采用结构等价。

示例:
1)
#include <stdio.h>
struct Point {
   double x, y;
};

struct Pos {
   double x, y;
};

int main() {
   struct Point p = {1.2, -2};
   struct Pos   q;

   q = p;  //出错:struct 不采用结构等价
   printf("q = {%g, %g}\n", q.x, q.y);
}

2)
#include <stdio.h>
struct Point {
   double x, y;
};

typedef struct Point Complex;

int main() {
   struct Point p = {1.2, -2};
   Complex      r;

   r = p;  //合法:struct 采用名字等价
   printf("r = {%g, %g}\n", r.x, r.y);
}

3)
typedef struct {
    char *id;
    int sym;
} Keyword;

Keyword keywords[] = {
    { "int",    INT    },
    { "double", DOUBLE },
    { "if",     IF     },
    { "else",   ELSE   },
    { "while",  WHILE  },
    { "read",   READ   },
    { "print",  PRINT  },
    { "return", RETURN },
    { NULL,     0      }
};

int keyword_lookup(char *id) {
    Keyword * q = keywords;    // 数组和指针采用结构等价
    while (q->id != NULL && strcmp(q->id, id) != 0)
        q++;
    return q->sym;
}

    五、语言的种类

    1. 命令式语言 (Imperative Language)
    编程以赋值为基础,通过值的改变实现计算,是对图灵机理论的实现。冯·诺依曼提出了实现命令式编程机器的体系结构。

    现实中广泛应用的语言大多数属于命令式语言,从 FORTRAN、Algol、Pascal、C,到 C++、Java 等都是。因为,今天的计算机仍属于冯·诺依曼架构,其机器语言以值的改变为特征,因此命令式编程语言容易编译为机器语言,实现高效的计算。

    2. 函数式语言 (Functional Language)
    实现了一种编程模型,将计算机运算看做是数学中函数的计算,避免了状态和数据 (变量) 的可变性。以阿隆左·丘奇的 lambda 演算为基础,强调无副作用、惰性求值、局部套用等理念。

    1958年,MIT 教授 John McCarthy 设计了第一个函数式语言 Lisp,用于符号数据处理,如微积分运算。之后出现了不同纯度的函数式语言:ML,Scheme,Haskell,JavaScript,Erlang,等。

    纯的函数式语言中,函数用于几乎一切的计算,包括加减乘除,并取代变量。变量是表达式的别名,只能赋值一次,值不能更改。函数调用无副作用,天生适用于并行编程。弥补了命令式语言的缺陷:并行编程非常复杂,依赖于信号量、锁,程序员不堪重负。

    六、语言的定义和标准

    1. 语言定义
    编程语言由语言参考手册定义。其中语法由文法规则或语法图定义,语义则由自然语言描述。

    2. 语言标准
    具有世界范围流行的语言,国际标准化组织为其制定的标准。如 C89、C99等。
 
    七、语言设计的目标

    1. 简单性
    简单性强的语言可读性也强,编写程序也容易。如 SQL、C 可读性强,C++ 可读性不强。

    2. 表达性
    语言的表达能力。

    3. 正交性

    正交 (orthogonal) 本是几何上的一个概念,表示垂直相交。一组两两正交的正交向量组撑起了一个线性空间,如二维空间、三维空间。空间中的任何向量都可以由这一组正交向量的线性组合得出。

    在编程语言领域,正交表示基本结构之间互相独立和良好隔离,并且能组合出一个 "功能空间"。在这组正交的基本结构中,任何一个不能由其它组合得到,即缺一不可。

    一组较少数量的基本结构,以及一套相互一致的结构组合(即正交性),比起提供大量的基本结构,要优越得多。

    正交性好的语言,语言结构简洁,语句和子句尽量少,语句的组合实现尽可能强大的功能。

    SQL 语言的正交性有口皆碑,C 语言的正交性也不错。C++ 的正交性很糟糕。

    4. 精确性

    不出现歧义性。

    5. 可靠性

    如 Ada 可靠、严谨。Java 是安全的。C 的定位是简单性、表达性和速度,可靠性在语言设计上稍欠,而由程序员保证。

    八、代码优化

    1. 指令选择
    像 x86、x86-64,指令有上千条之多,选择哪些指令,需要在效率和复杂之间平衡。

    2. 寄存器分配
    局部变量、临时变量尽量存放在寄存器中。但寄存器是宝贵资源,哪些变量分配寄存器,哪些溢出到内存,是研究的大热门。

    3. 删除多余指令

    4. 删除死代码

    5. 常量折叠
    编译时计算。x = 100 + 200 + y;  =>  x = 300 + y;

    九、扩展 cmm 项目

    1. 实现函数调用

    2. 增加 double, char, string 等类型

    3. 允许自定义 数组、结构体、共用体、指针 等类型

    4. 更精准的错误检测

    5. 多个源程序的编译

    6. 链接

    7. 库函数

    8. 垃圾回收

    十、编译技术展望

    1. gcc

    2. clang

    3. 并行技术

 


打赏
最近浏览
wumaojie  LV2 2019年6月19日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友