diff --git a/Ch1-1-History.tex b/Ch1-1-History.tex new file mode 100755 index 0000000..88f9680 --- /dev/null +++ b/Ch1-1-History.tex @@ -0,0 +1,160 @@ +\section{引言} + +软件是以计算为核心手段实现应用目标和价值的解决方案。从1966年首届图灵奖至2018年的53次颁奖中,属于软件领域的有37次(69.8\%),其中以程序设计语言、编译和操作系统为主获奖的有22次获奖,还有4次数据库获奖。作为本书第一部分的开篇,本章将简要回顾软件和软件技术的发展历程,通过梳理软件发展脉络,总结软件学科的基本内涵、关键问题、研究方法和发展规律,为第二部分学科发展战略提供基础。 + +\section{软件发展简史} +\subsection{人力/机械计算时代} +计算是人类思维的基本形式之一。人类历史上最早的计算设备是中国算盘。到东汉年代,提花机(参见图\ref{fig:1-1})的设计中蕴含了用编程方式编织特定图案的思想,类似的设备1805年欧洲出现了Jacquard‘s Loom(参见图\ref{fig:1-2})。1842年人类的第一位程序员Ada Lavelace为Babagge的分析机写了第一个程序,功能是计算Bernoulli数(参见图\ref{fig:1-3},\ref{fig:1-4})。可见早在机械计算时代,可编程的思想已经萌芽。 + +\begin{figure}[htbp] + \centering + \begin{minipage}[t]{0.48\textwidth} + \centering + \includegraphics[width=5cm]{fig1-1/1-1.png} + \caption{提花机} + \label{fig:1-1} + \end{minipage} + \begin{minipage}[t]{0.48\textwidth} + \centering + \includegraphics[width=5cm]{fig1-1/1-2.png} + \caption{Jacquard‘s Loom} + \label{fig:1-2} + \end{minipage} +\end{figure} + +\begin{figure}[htbp] + \centering + \begin{minipage}[t]{0.48\textwidth} + \includegraphics[width=5cm]{fig1-1/1-3.jpg} + \caption{Babagge分析机} + \label{fig:1-3} + \end{minipage} + \begin{minipage}[t]{0.48\textwidth} + \centering + \includegraphics[width=5cm]{fig1-1/1-4.jpg} + \caption{Babagge分析机的第一个程序} + \label{fig:1-4} + \end{minipage} +\end{figure} + + +Computer一词历史上出现在1613年,用来指完成演算或计算的人员。这种说法一直到19世纪末后工业革命产生了主要目标是用来演算的机器为止\footnote{https://www.computerhope.com/issues/ch000984.htm}。著名的哈佛大学哈佛天文台在1877年至1919年期间雇佣了一批妇女作为处理天文数据的技术工人。在电子计算机出现之前的人力和机械计算时代,Mathematic Tables项目是最大最复杂的计算项目,组织这类项目的关键就是编程的基本思想。Gertrude Blanch女士作为“数学的导演”和“计算的经理”,设计了人力计算团队执行的“算法”。这些算法和错误检测的设计思想作为超越函数的计算标准延续了数十年。逐渐地,也出现了表达编程描述形式和记号,例如1921年Lillian和Frank Gilbreth的过程图(Process Charts,参见图1-5),与后来的程序流图十分类似;又如1940年IBM的W.J. Eckert提出的打孔卡(参见图1-6)。我们可以看到,计算和编程是紧密耦合的,而编程的结果事实上是给出了一种计算应用(数学计算)的解决方案,它可以有人力计算或机械计算完成。然而,在那个时代,还未形成通用计算和编程的思想。 + + +\subsection{电子计算时代} +四十年代出现了电子计算机,计算机先驱们相继研制了Colossus(1943)、ENIAC(1946)、EDSAC(1949)和Mark I(1949)等计算机。EDSAC作为第一台存储程序结构的电子计算机打开了通用计算的时代。程序是通过一种微开关的形式加载到机器硬件上。到五十年代后,才出现了用户和计算机之间的简单交互。Grace Hopper在1951年和1952年为UNIVAC I编写了A-0系统,这是第一个电子计算机的编译器,从今天的角度看A-0更像现代编译器概念的Loader或Linker,无论怎样都是第一个系统软件。UNIVAC I的程序有一组子程序和参数序列组成。两年后,A-2系统成为了第一个开源软件。早期系统是驻留管理程序,它将程序从纸带或者穿孔卡上读到计算机中加载。这种技术直接形成了历史上第一个商用操作系统,1956年IBM 704的操作系统。五十年代后,人们开始意识到1936年提出的图灵机模型的理论意义,图灵机成为计算机科学发展的理论基础。通用图灵机和通用计算使人们进一步认识到可编程是计算的基本属性,人们通过编写程序使得计算机完成指定的任务。 + +\subsection{软件和软件工程的出现} +“软件”一词最早出现在1953年兰德公司R.R. Carhart的报告中,用来说明讨论可靠性时与硬件相对应的“人因”。而人们现在一般认为“软件”的术语来自John W. Tukey在1958年的论文。文中指出 “软件由精心编写的解释程序、编译器和自动编程等组成,它们至少象电容器、晶体管、电线和磁带等现代计算机硬件一样重要”。1968年,或许是巧合,出现两个软件发展史上的重大事件。一是,软件与硬件的解绑;二是,软件工程会议的召开。这两个事件的背景都与IBM著名的IBM S/360系统相关。 + +软件依附在硬件之上解决应用问题。早期的计算机系统中硬件和软件时捆绑的。所谓“捆绑”,指IBM在收费上采取只考虑硬件价格而软件和系统服务免费的策略。这在当时对于用户是很有吸引的,也增强了公司的竞争力。到1964 年,情况发生了变化,IBM宣布了新的IBM S/360系列,希望能够升级硬件系统而不需要替换或改变用户的应用程序。而稍后RCA也宣布了其新的Spectra 70系统与IBM 360兼容。这使得IBM难以阻止RCA在市场上“免费”使用IBM的软件。1968年,IBM宣布了其软件和硬件系统的解绑,改变了软件的商业和竞争模式。自此软件从计算机系统中与硬件的剥离,获得了可以独立发展的空间。可以看到,除了商业上的反垄断和市场竞争因素外,软件本质上“解决方案”的独立性和计算平台抽象为解绑提供了历史必然和技术可行。自此,人们逐步认识到软件是计算机系统的灵魂,它向下管理计算机系统的各类资源,向上满足用户对计算机系统的应用需求。 +第二个事件是软件工程的兴起。计算机能力的快速提高和软件复杂性困难,出现了“软件危机”现象,例如,IBM 360操作系统OS/360的进度、开销和可靠性均不尽人意。NATO在1968年举行了首次软件工程会议,人们逐渐认识到需要如同其他领域的工程方法一样,系统化地进行软件开发。正如Margaret Hamilton在开发阿波罗在轨飞行和导航系统项目中明确指出,“我努力使软件具有合法性,使得构造软件的活动要受到应有的尊重,因而我开始用‘软件工程’将其与硬件和其他类型的工程区分开来,成为整个系统工程的一部分”。软件工程的出现不仅激活了软件发展的巨大活力,也隐喻了软件发展的外在驱动力,不断增长的应用需求和不断增长的计算能力。 + + +\subsection{软件发展的主线} +软件作为计算灵魂与计算发展紧密相连。追溯软件发展可以有多条线索,既可以考察计算机系统平台、应用和计算形态的发展,也既可以采用程序设计语言、系统软件、软件开发方法等角度。从需求应用看,从军事计算需求起步,逐步从商业计算、个人计算、网络计算、云端计算、到如今泛在计算;从计算平台看,从主机时代、微机时代、互联网时代到人机物融合时代,计算设备的多样性、能力、范围不断扩展。相应的,面向需求,满足各类质量、进度和成本约束,软件的语言从机器语言、汇编语言、高级语言、发展到领域语言,软件开发方法从结构化方法、对象化方法、构件化方法、服务化和网构化方法到智能化方法,系统软件平台从批处理、交互式、网络化、云边端融合系统软件。 + +软件作为问题解决方案,其结果是认识空间的表达。Sapir-Whorf的语言相对论假设对语汇的重要性给出了一个表述。其弱版的语言相对论是指语言影响思维与决策;而强版的语言决定论则指语言决定思维与认知边界。认识软件的切入点是认识各种软件抽象。它们构成了软件方法学的语汇,包括但不限于程序设计语言设施、软件构件、软件服务等。而系统软件的核心在于实现抽象,应用软件在于使用抽象。不同层次的抽象、抽象的计算实现和使用组成了软件发展的脉络。我们试图以软件各种抽象为主线来梳理和汇聚软件发展的基本历程。 + +从最初计算机系统上机器指令开始,人们不断地在建立抽象,例如:汇编语言中的宏指令抽象,定义了具有宏名的一段汇编语句序列;在结构化高级语言的数据结构抽象,过程抽象;面向对象方法中的类和继承;构件化方法中的构件抽象;服务化方法的服务抽象;以及网构化方法的主体抽象;智能化方法语言中的学习赋能抽象等等。语汇抽象之间的关系与软件定义栈呈现一个垂直吻合的关系。例如,在典型的大数据处理系统(Google)中,我们可以看到接口与服务、方法与设施、虚拟化与实现等不同层次组成的抽象栈,它们分别对应着Web服务、MapReduce、Dryad、Pregel、BigTable、集群调度、分布式文件、操作系统等抽象层。 + +以程序设计语言和相应程序接口为基础,形成了软件的基本抽象。与数学抽象的不同,软件抽象是可编程的单元并有计算之实现。围绕这些抽象软件学科的发展呈扇形展开,分化出以建立抽象为主要内容的软件理论和方法学;以实现抽象为主要内容的系统软件;以使用抽象为主的软件开发和工程。参见图1-X。 + +军事和科学计算是计算应用的最初需求。面向科学计算建立的抽象成为软件发展的早期里程碑。为了满足数值计算的需求John Backus1953年发展了Fortran语言,是历史上第一个正式推广的高级程序设计语言,1957年在IBM704计算机上实现。Fortran语言提供的抽象对用数学公式表达的问题求解提供了直接支持。多年的版本更替,Fortran语言至今仍在使用。Fortran的主要贡献者获得了图灵奖。1960年,面向常规商业信息处理,COBOL语言发布,成为COBOL-60。COBOL提供了面向周期性循环处理和数据变换的抽象,适合于报表、情报、计划编制等商业数据处理,如今仍有应用。同一时间段,面向通用计算的算法语言ALGOL 60诞生,成为ACM当时算法描述的标准,它提供了数据结构、块结构、递归等设施。ALGOL语言的意义重大,一是它确立了结构化高级程序设计语言设计的基础,之后的Pascal、C、Java等强制式程序设计语言的基础;二是它催生了试图严格或形式化定义语言和程序的一大批软件基础理论成果。ALGOL 60的主要贡献者Peter Naur获得了2006年图灵奖。60年代末至80年代,历经Simula 67、Smalltalk、C++等语言,面向对象程序设计范型形成,提供了类、对象、方法、消息传递、继承等设施,建立了封装、抽象和多态等机制。面向对象语言的创立者也获得了图灵奖。与强制式程序设计语言不同,50年代末人们还探索了声明式程序设计语言,其代表是基于Lambda演算的函数式语言LISP。它提供了用于问题求解的函数抽象,首次在语言中支持递归函数定义。LISP的设计思想深刻地影响了ML、Haskell等函数式程序设计语言的发展。随着人们对程序设计安全可靠、便捷有效等需求的提高,以及计算平台向并发、分布、异构发展,程序设计语言呈现了两方面走向:一是,程序设计范型的融合,例如面向对象语言和函数式语言的融合并支持并发、安全计算,出现了Scala、Rust等程序设计语言,展现了强劲的势头;另一方面是,面向特定领域的语言受到了重视,它们针对领域应用提供高效便捷的抽象,例如面向大数据处理的Map Reduce面向区块链智能合约的Solidity。 + +60年代末软件工程思想的出现,使得人们认识到如何面向应用建立软件开发方法和软件工程模式的重要性。软件开发方法中的诸多抽象大多来自于程序设计语言的思路。例如,70年代的结构化系统分析和设计方法、80年代的面向对象分析和设计、90年代基于构件的软件工程、新世纪的面向服务/网构化的软件工程等等。软件开发和程序设计在抽象上尽可能地保持了一致或相容,使得软件工程模型不同阶段、不同层次地抽象有着较好的对应。 + +程序设计语言向上要面向问题求解方法的表达,向下要在计算机系统上实现。围绕语言的语法、语义和语用等方面的程序理论和问题求解的计算理论成为了软件理论的重要部分。从ALGOL60开始,关于程序理论的研究就开始了,其基本内容是在计算理论的基础上建立程序的形式语义,并对程序及其性质进行推理,本质是基于数学的方法来建立抽象及抽象之间的联系。在60年代到70年代,人们建立了程序设计语言的操作语义学、公理语义学、指称语义学和代数语义学。程序语言与形式语义的研究紧密联系,例如,1974年Barbara Liskov提出了抽象数据类型的程序设计思想,建立了现代面向对象语言的核心特征,包括强类型检查和通用类型支持,支持了对象化方法语言中的类抽象。以形式语义学为基础,人们长时期探索程序的形式开发和形式验证等形式化方法和技术以提高软件生产率和软件质量,取得显著的进展,例如模型检验获得了2005年图灵奖。与程序相关的问题的求解判定和算法复杂性也成为程序设计语言设计和形式化方法的重要内容,例如Gradual类型的引入。 + +随着硬件能力快速提高,以编译器和操作系统为代表的系统软件成为建立抽象、使用抽象来实现更高级抽象的焦点。事实上,程序设计语言中许多重要概念来自于编译器和操作系统的设计。John Cocke在解决上下文无关语言的有效扫描中发明了动态程序设计范型,而Floyd为了构建层次化自顶向下的扫描器发明了递归协程序作为抽象结构。Floyd希望能发现语言支持的新范型(抽象)。这说明了抽象是用来支持相对应的设计方法,也就是问题求解的方法。 + +到六十年代,集成电路的兴起增强了计算机的能力,操作系统出现了不少新技术并变得强大复杂。典型的技术有多道程序设计、分时、实时、多处理器技术等等。70年代,操作系统的设计进一步发展,形成了UNIX操作系统,成为当今主机操作系统的基础。80年代,商业计算和微处理器时代到来,出现了一批微机和工作站操作系统,代表的是MS-DOS,Linux、Solaris 和Windows等。90年代,随着计算机网络和网络就是计算机的推动下,在主机和微机操作系统的基础上,中间件或网络化操作系统逐渐成为系统软件的新的增长点。进入新世纪后,以iOS和Android代表的移动操作,和主机操作系统向数据中心扩展的云操作系统形成了云端计算的软件基础设施的基本格局。 + +操作系统中的三个基本元素是抽象、机制和策略。而其抽象的基本设计原则是机制与策略的分离、共性的沉淀。典型的例子有进程和进程管理、线程和并发、调度、内存管理、进程间通信、I/O管理、虚拟化、分布文件系统、分布共享内存、安全与隐私抽象-Ownership等等。在实现这些抽象的过程中,人们发现并设计了计算的原理和法则,例如局部性原理、名字映射、分而治之、信息隐藏等等。与实现抽象密切相关,系统软件与计算平台的演进紧密相关,例如在网络化时代,操作系统的API是网络操作的API,而在云边端的时代,操作系统通过协议软件、RPC等来集成。Barbara Lis-kov讨论了系统、语言和抽象的关系,指出抽象对系统组织的作用,例如用进程和软件层次来组织复杂系统。为了应对操作系统设计中可靠性、安全性、可配置、可扩展和多处理器程序设计等挑战,微软的Singularity OS的首要任务开发新的抽象,包括平台的抽象指令集、操作系统和应用统一可扩展的体系结构和一阶的应用抽象。特别的是应用抽象递归的应用到操作系统自身,包括内核和其他OS构件。Singularity OS的后继Midori OS支持了微软西海岸和亚洲的自然语言搜索服务。Midori表明了合理的抽象和软件栈能在内存、类型和并发安全之上构建系统和应用,性能和安全并不是对立的。 + +回顾软件学科发展,在认知空间中,人们一方面不断的建立抽象,一方面不断的在计算平台上实现抽象,两者相辅相成,螺旋上升;与此同时使用抽象的方法和对高层抽象的需要促进了方法和技术的发展。例如,结构化程序设计开创了程序设计得到的程序具有良好的结构,在这个指导思想下,问题求解可以看作是一系列的分解过程,即从一个较高层的过程,初步的加入细节得到较低层的抽象,从而完成整个程序。逐步精化和层次化的程序结构是结构化程序设计的基本原理。在结构化程序设计的基础上,当程序员在某个抽象层次上使用下一层次提供的抽象时并不需要考虑底层的实现细节。然而高级程序设计语言不可能以内嵌的方式提供问题求解需要的所有抽象,需要一种方式可以从内嵌类型构造不同层次抽象的能力。这些动机促使了抽象数据类型的出现。抽象数据类型用抽象对象上一组操作的方式定义了该类抽象对象,即用类型上的操作来定义新类型。它一方面封装了底层操作抽象的细节,又构造了一组新的类型抽象。如图,结构化抽象与THE OS、C与UNIX、面向对象与CORBA和EJB、服务化与Docker虚拟机交相辉映,形成了以计算为手段的解平台提升,并与结构化、对象化、构件化、服务化等软件开发方法携手同行,成为人工科学边界物的基础。 + +软件发展的核心是管理复杂性。从平台空间到应用空间的认知与问题求解鸿沟是作为解决方案的软件来提供或弥补的,相应的软件形态也在逐步的演变丰富。在计算机诞生后五十年中,软件的表象发生数次变化。从早期的“程序=数据结构+算法”的初级抽象,到“软件=程序+文档”,结构化程序设计关注在于管理结构复杂性。进入网络化时代后,交互复杂性和规模复杂性日益突出,体系结构加设计模型抽象、服务加组合抽象为管理这些类复杂性应运而生。进入大数据时代后,知识复杂性和领域复杂性需要纳入软件,软件在程序加文档的基础上需要抽象知识、数据和能力。软件的发展从微观上看,从40年代到60年代解决基础问题,到80年代管理结构复杂性为主,到本世纪初管理交互复杂性为主,到近来以管理异构、互联的规模复杂性和社会技术复杂性。建立、实现、使用抽象的循环迭代不断往复,推进着软件技术的发展。 + +抽象是从制品的角度来认识、构造和演进软件。而软件作为人类的智力产品,与这条主线相配合,组织和管理制品在生命周期中的过程复杂性是极为重要的,也构成了一条与抽象相配合的辅线。它的演进与软件的应用、平台和认知空间的演进互联互动,从早期的作坊式生产组织方式、企业化生产组织方式发展到网络化智能化时代的社会化生产方式。企业化生产组织方式主要有软件过程(1970)、CMM(1988)、SCRUM(1995)、RUP(2000)和外包(2001);社会化生产方式有开源(1997)、Git(2005)、StackOverflow(2007)和DevOps(2008)。 + + + +\section{软件学科的内涵、发展规律和基本架构} +\subsection{内涵与学科特征} +软件作为计算平台上实现应用价值的解决方案,是最存粹的人工制品,其内涵特征包括了三个方面: +\begin{itemize} + \item [-] 功能性:以何种结构和行为 + \item [-] 目的性:达成什么应用目的 + \item [-] 适应性:何种环境依赖之下 + +\end{itemize} + +软件学科是以软件为研究对象,研究设计和使用软件及其规律的学科。其核心内容是以计算为工具的问题求解方法论,目标是达成效能、效率和价值的统一,知识体系包括了理论、方法、工具、环境和生态。N. Wirth在“软件工程简史”一文中指出“如果说我们能从过去学到什么,那就是计算机科学本质上是方法论学科。它开发并教育在广泛不同应用的共性受惠的知识和技术”。我们认为,在这个意义上,软件学科实质上就是Wirth所说的计算机科学。之所以我们使用了软件科学,是因为有了时代的扩展(参见第二篇引言)。 + +软件的功能性、目的性和适应性,使得软件学科呈现出了艺术、科学和工程共存的学科特征。这源自于软件本身融合了人类活动、数学物理规律约束的计算模型和装置、以及面向应用价值的工程设计。例如,软件的算法设计是艺术,而算法分析是科学;程序设计是艺术;而程序正确性是科学;进一步软件开发是工程,而软件分解与抽象及其正确性是艺术与科学。软件之目的性是其工程属性的来源,而功能性的设计及设计的柔性孕育了多样的艺术性,软件最终运行的计算平台的物理和自然属性内生了软件发展遵循的科学规律。而艺术、科学和工程在软件发展的不同阶段和侧面会相互渗透乃至相互转换。归根到底,其目的性价值、软硬平台与外部环境所形成的功能及界面适应性是其核心,也形成了软件成为万能集成器和粘合剂的基础设施地位。而这一特性,也形成了软件作为核心的不同层次栈组成计算载体,包括语言、平台、结构和框架。 + +\subsection{发展的基本规律} +随着网络时代的到来,软件网构化和服务化,解耦和绑定的周期性出现,驱动力主次的周期性变化,使得软件变化成为常态。“变是不变”形成了软件发展的规律。我们从两个方面来认识软件学科发展的规律:第一,本学科发展的驱动力是什么?第二,本学科的研究方法论是什么。 + +\subsubsection{发展的驱动力} +软件是刚性约束和超级柔性的产物。平台和应用目的可计算、复杂性和正确性形成了软件需要遵循的刚性约束,而内在的各种方法学引导,功能和适应性设计则形成了系统的柔性多样,也给予了软件学科无穷的发展活力。作为人工制品的界面物属性,软件学科发展的外部驱动力来自于两个方面:不断增长的应用需求和不断增强的计算平台;而其内在驱动力也来自于其核心问题的解决,即软件的效率和质量,即提高软件生产率,保障软件质量,降低软件成本,以及不断发展的人本属性,包括人的认知规律和人力资源管理的深化与提高。 + +\textbf{外在驱动力} + +回顾软件发展的历史,可以看到软件的外在驱动力主要来自于两个方面。第一个方面是来自于计算平台的发展,简称平台驱动力;第二个方面是应用需求的增长,简称应用驱动力。平台的变迁形成了软件所依赖的平台空间;而应用的增长形成软件所解决的问题空间。在平台空间和问题空间的之间,形成了软件作为界面物所需具有的功能、目的和适应形成的认知空间。软件的发展是着三个空间变化、渗透和互动的产物。 + +应用和平台的诉求,应用拉动,平台提高,推动软件的发展。从应用驱动力的角度,软件的范围扩展,渗透力增强。不断增长的应用诉求拉动了软件技术从早期的科学计算应用,扩展到了等各类不同应用,软件学科的无可比拟的渗透力变得空前的强大,软件的形态、开发方法和运行形态等诸多方面发生了巨大的变化。从平台驱动力的角度,计算平台从Von Neumann计算机到网络就是计算机、从端网云是计算机到全球泛在计算,形成了从封闭、静态环境(单机计算平台)到开放、动态环境(网络计算平台)的态势,造就了软件发展的不竭动力,使得软件所能提供的解决方案的解空间更趋科学、高效。在应用驱动力和平台驱动力的联合作用下,软件正走向“定义一切”。 + +\textbf{内在驱动力} + +作为计算平台上问题解决方案的方法论,软件学科需要阐明一些基本问题,这些基本问题的解决支撑了软件学科发展,即:可计算性理论,解决问题能不能在计算平台上求解的问题;算法设计与分析,解决问题能不能在计算平台上高效能行求解的问题;软件方法和技术,解决问题能不能有效控制复杂性;软件基础理论,解决软件能不能可信的问题。前两个问题解决问题的能行求解;第三个问题解决复杂性的工程控制方法;第四个问题评价获得的解是否符合价值观,达到目的。我们认为,作为问题求解的方法学,提高求解效能(单位成本的软件生产率和软件质量)是软件发展内在驱动力,而抽象和复杂性控制成为学科发展的核心要素。 + +从技术角度看,灵活、可变、适应性是软件不变的需求。软件在语言上追求更具表达能力;在方法上符合人类思维,易构造,易维护;在系统上更高效可靠。围绕抽象和复杂性控制,软件学科形成了从模式化、形式化、自动化到智能化的基本手段,由软件结构、开发结构和组织结构组成的工程模型走向开放化。 + +\subsubsection{学科方法} + +从研究的角度,软件学科需要建立构造并在计算机上运行问题解决方案的科学和工程基础。从应用的角度,我们需要建立开发软件制品的方法和过程来高效和节约地构建软件系统。在软件学科中,基本方法可以归为三类,即理论方法、实验方法和设计方法。 + +\textbf{理论方法} + +理论方法首先给出对象的定义描述,并假设它们之间可能的联系,通过证明来判断这些联系是否成立,并解释所得到的结果。源于以图灵机为代表的形式化计算模型的奠基性贡献,使得计算平台伊始便具有刚性的数学理论约束,使得数学天然地进入了计算机理论研究。通过建立形式理论、推理获得结果并解释结果,形成了软件作为数学对象来研究和开发的方法学。这种方法提供了开发模型和理解模型边界的分析框架,在软件正确性方面发挥了重要作用。理论方法根植于数学,将计算视作数学对象开展研究。 + +\textbf{实验方法} + +实验方法或者建模属于实验科学方法。它首先形成基于假设构造一个模型,开发统计/量化方法,应用到案例上,度量和分析,来确认所提出的模型。这种模式是一种变革性的改进,例如提出一种新的方法和工具来完成软件开发。仅仅提出一种方法还不够,需要有度量和分析的方法来说明方法和工具较已有方法的先进性。实验方法根植于自然科学方法,源于科学假设,系统建立模型,验证并确认这些假设。与其他科学方法类似,实验手段中计算手段的引入使现代实验方法有了新的途径。对于软件科学的研究来也是这样,可以利用计算的手段开展软件的实验研究,包括用软件模拟软件的模型方法和用数据科学方法来研究软件及其环境的现象和方法。 + +\textbf{设计方法} + +自然科学中理论方法和实验方法之外,人工科学的特有方法是设计方法,它着眼于为了解决一个问题来工程化构造一个软件。它的基本过程是表述需求、表述规约、设计和实现系统并测试系统。设计中不断对已有的软件解决方案观察,提出更好的解决方案,建立/开发、度量和分析,重复直到难以改进。这种模式是一种演进改进的方法,是一种模型改进的方法,关键在于仔细的分析和度量。设计方法根植于工程,源于面向问题,通过系统的设计过程来构造解决方案。 + +软件科学构成了人工科学的基础。其核心是模型抽象。以模型为数学对象,形成了软件学科的理论方面;从软件到软件模型,形成了软件学科的科学方面,从软件能否构造一个符合该软件系统的模型,并对软件开展预言;从问题、软件模型到软件,形成了软件科学的工程方面,面向问题获得求解模型并构造一个符合该模型的软件系统。上述三个方面在软件科学的研究中并不是正交的,往往会联合在一起共同解决学科问题。它们各自具体不可替代的作用,理论方法描述和揭示软件模型及对象之间的联系,实验方法可以运用这些联系来预言软件行为并与现实世界比较,设计方法则是通过这些联系的科学发现来设计完成解决方案。这三者的紧密联系也使得软件科学区别于数学、自然科学和传统工程科学。 + +\begin{itemize} + \item \textbf{举例}:基于大代码的软件自动生成方法就综合软件科学中的理论、实验和设计方法。程序综合是计算机科学的明珠。其理论研究是长期以来的科学问题。演绎推理的理论方法是其重要途径,形式规约开始构造一个正确的程序,自动定理证明和归纳综合是其基本思路,并逐步发展到了归纳推理。近来随着海量代码的累积,实验统计的方法逐步兴起,以实验方法从代码数据中学习,建立程序综合和推理的启发式预言有效地提高了综合效率。以归纳推理和统计推理相结合的程序综合设计方法成为了当前软件自动化研究的重要趋势,在代码自动生成、代码修复、人机协同编程等方面取得了重要进展。 + +\end{itemize} + +\subsection{软件学科的基本架构} +从目前的一级学科划分看,软件学科横跨了计算机科学与技术,软件工程、网络空间安全等三个一级学科。特别是,与计算机软件与理论二级学科和软件工程一级学科关系密切。 + +与本科生的计算教育学科相比,软件学科横跨了ACM/IEEE计算教程等五个学科,即计算机科学、计算机工程、软件工程、信息技术、信息系统。它们的覆盖关系如图1-X所示。 + +我们着眼于软件学科发展历程的回顾,重新梳理,就现状划分了三个子领域,程序设计语言与理论、系统软件、软件工程。其中,程序设计语言与理论的核心内容是建立抽象;系统软件的核心内容是实现抽象;软件工程的核心内容是使用抽象。它们与我国目前一级学科、ACM/IEEE计算学科的关系如图1-X所示。 + +软件强大的渗透性,使得软件和产业紧密相联,并产生了软件产业。软件的问题解决方案和人工制品特性、软件发展的外部驱动力决定了其形成产业的必然,而强大的产业需求不断地拉动软件的发展,软件学科与软件产业相互促进,共生共荣。 + +\section{本章小结} + +本章通过梳理软件发展的脉络,指出了软件是以计算为核心手段实现应用目标和价值的解决方案。可编程是软件的基本特征,建立抽象、实现抽象和使用抽象是软件发展的主线。不断增长的应用需求和不断增强的计算平台构成了软件发展的外部驱动力,而控制复杂性、提高单位成本的软件生产率和软件质量是其发展的内在驱动力。软件作为最为复杂的人工制品,软件学科是以软件为研究对象,通过科学方法、实验方法和设计方法等途径,研究设计和使用软件及其规律的学科。 + +第一篇的后续几章分别介绍程序设计语言与理论、系统软件、软件工程、软件产业等方面进一步阐述学科领域的内涵和外延、关注解决科学问题,以及对应的发展历程,现状和存在的主要矛盾。目的是从各方面来阐述软件发展的学科特性,把握学科现状和发展规律,为展望学科的未来发展奠定理性思考的基础。 + +\section{参考文献} + +\begin{itemize} + \item [] [1]. Liskov \& Zilles. Programming with Abstract Data Types, ACM SIGPLAN Notices, 1974 + \item [] [2]. Floyd. The paradigms of programming, CACM 1979 + \item [] [3]. Watts S. Humphrey. Software Unbundling: A Personal Perspective. IEEE Annals of the History of Computing. 2002 + \item [] [4]. H.A. Simon. The Science of the Artificial. 1968 +\end{itemize} diff --git a/Ch1-1-Intro.tex b/Ch1-1-Intro.tex deleted file mode 100644 index 324f6aa..0000000 --- a/Ch1-1-Intro.tex +++ /dev/null @@ -1,7 +0,0 @@ -% !TEX root = main.tex - -\chapter{引言} - -bla bla - -\section{第一节标题} \ No newline at end of file diff --git a/Ch1-2-ProgrammingLanguage.tex b/Ch1-2-ProgrammingLanguage.tex new file mode 100755 index 0000000..bb26a52 --- /dev/null +++ b/Ch1-2-ProgrammingLanguage.tex @@ -0,0 +1,249 @@ + +\section{引言} + +软件工程师在开发软件系统时,不可避免地要用到某种程序设计语言。顾名思义,程序设计语言是程序员用来描述程序行为的语言。在计算机科学领域,曾出现过数百种程序设计语言。TIOBE给出目前常用程序设计语言的流行度排序,从高到低有:Java、C、Python、C++、C\#、JavaScript、PHP等[23]。Sebesta[1]从高级语言机制的设计角度对程序设计语言进行了深入细致的介绍和比较。大多数新程序设计语言的创建都受以前语言概念的启发。较旧的语言仍然是新语言的坚实基础,而新出现的程序设计语言使程序员的工作变得更加简单。 + +程序设计语言的定义可分为语法、语义等方面。语义表示程序的含义,由静态语义和动态语义组成。静态语义指程序编译时可以确定的语法成分的含义;建立在转换/迁移系统上的动态语义则描述程序如何执行。 + +\section{程序设计语言} + +在计算机发展的早期,人们往往是用二进制(0/1序列)给计算机发指令。这显然很不方便。后来,逐渐出现了汇编语言以及各种高级语言。一般来说,提高软件开发本身的效率与质量需要更抽象更高级的程序设计语言;而提高现实计算机硬件系统的利用率和执行效率,则需要使用较低级的程序设计语言,这样程序可以更直接地控制硬件资源。较通用的程序设计语言适用于广泛的应用领域和应用场景,可吸引大量的语言使用者,积累充足的遗产代码,便于培训与推广共享资源;但高度通用的语言设计上难以兼顾开发效率与执行效率。很多针对特定应用领域的程序设计语言更容易通过合适的语言机制同时改善软件开发与执行的效率。多样化的编程接口具有程序设计语言功能,但缺乏相应的编程框架甚至程序库等。这类接口反映了相应的编程模型的特点,实质上起到了程序设计语言的作用。 + +程序设计语言的发展既要遵循自身理论与模型的内在规律,也受到计算机系统发展的驱动和行业应用需求发展的推动。不同语言不同程度地受这些因素推动。但从程序设计语言发展历史角度看,应用需求的影响明显处于主导地位。新出现的程序设计语言通常是应对新兴应用或者新兴计算机体系结构的需要。 + +\subsection{语言的设计、实现及生命期} +\subsubsection{设计} +一般说来,程序语言的设计应该遵守以下原则:能够很容易的理解;能够清晰、准确地表达计算意图;确保程序不会导致意外;每种语言构造的组合都是合法的;相似的特点有相似的表示和行为;能够很容易发现错误并纠正;能够给用户提供加入新结构的机制;允许程序在不同机器和系统间的移植;能够编写对应的转换器或解释器。 + +语言设计在实践中有三个角度:从程序设计语言理论角度出发设计的语言如Pascal、Ocaml、X10等十分关注语言语义的清晰性、灵活性、简洁性,往往直接反映了理论领域的创新成果;从系统软件与体系结构角度出发设计的语言如图形处理器支持的CUDA,关注如何充分利用系统结构的特点来优化性能;从应用角度出发设计的语言如XML、PHP、Julia等关注与目标应用的契合度以及编程的便易性。 + +某些语言如数据库查询语言SQL简洁地表示数据表格间的代数关系,大幅简化了对数据库的查询;深度学习编程框架TensorFlow[5]、PyTorch等辅助编程者方便地生成神经网络结构并根据学习算法自动生成反向网络。这些语言或框架追求编程简单性,虽然简化了循环和递归这样的图灵可计算性的关键语句,但仍然反映了一定的程序设计模型。 + +\subsubsection{实现} + +语言的传统实现方式分为从高级语言到机器代码的静态编译与直接对高级语言程序解释执行两种方式。如果存在中间语言,在不同层次分别可能采用不同方式混合实现,如避免在运行时的编译性能消耗和内存消耗的运行前编译(ahead of time,简称为AOT)与根据当前硬件情况实时编译生成机器指令的运行时编译(just-in-time,简称为JIT)。编译技术仍然是语言实现的关键技术。一方面类型检查等静态程序分析均在编译阶段实施,另一方面代码生成过程中的优化技术是对程序员屏蔽硬件复杂性的主要手段。 + +近年来,随着计算机系统结构的多样化和复杂化,程序设计语言出现了许多新的形式。例如,并行编程模型OpenMP使用预编译制导语句插在C或Fortran的代码中,描述了多线程并行。尽管OpenMP本身不具有完整的独立语法,但因为反映了与串行C语言不同的共享变量式并行编程模型,我们也可以称之为新的“语言”或者至少是新的“语言机制”。 + +通用语言的程序可以像OpenMP那样插入新的语言机制的语句,也可以反过来在新风格的程序中插入通用语言的子程序。这一方式在大数据处理编程框架MapReduce、Hadoop、Spark中得以应用,不仅简化了分布式并行数据处理编程,而且允许程序员设计灵活高效的程序用于数据处理。一些编程模型的实现甚至不引入任何新的语法扩展,仅仅以子程序库的形式出现。比如,科学计算中广泛使用的MPI由C和Fortran程序库实现,支持多种形式的消息传递通讯。 + +\subsubsection{发展} + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.80\textwidth]{fig1-2/2-1.png} + \caption{常见程序语言的发展脉络 + \label{fig:2-1}} +\end{figure} + +自20世纪60年代以来的发展历程看,程序设计语言的抽象级别显著提高。历史上曾出现过将程序设计语言分为四代的提法: + +\begin{enumerate}[1)] + \item 机器语言:由二进制0、1代码指令构成,不同的处理器具有不同的指令系统。由于机器语言难编写和维护,人们已很少直接使用这种语言。 + \item 汇编语言:汇编语言指令可以直接访问系统接口。由汇编程序翻译成的机器语言程序效率高。但同样难以使用与维护。 + \item 高级语言:它是面向用户的,独立于计算机种类与结构。因此易学易用,通用性强,应用广泛。图\ref{fig:2-1}给出了常见高级程序设计语言的发展脉络,其中箭头指向的程序设计语言借鉴了前驱的设计思想。 + \item 非过程化语言:使用这种语言编码时只需说明“做什么”,不需描述算法细节。数据库查询语言是其中的一种,用户可以对数据库中的信息进行复杂的操作。 +\end{enumerate} + +在程序设计语言发展最初阶段,程序设计语言按照主要编程范式,可以被归类为面向过程式的、面向对象式的、逻辑式的、函数式[22]的等。随着C++、C\#等语言的出现,传统分类之间的界限逐渐变得模糊。现代的编程语言往往具有若干种类编程语言的元素,这就是所谓的多范式编程语言。而多范式程序设计语言也是一个越来越明显的趋势。 + +一个成功的程序设计语言从探索到推广、接受和最终成为行业标准往往经历以下四个阶段:第一阶段,新兴应用与系统的软件开发在早期开发过程只能采用已有的程序设计语言配以一定的软件工程方法;第二阶段,为提高软件生产率,多种语言工具开始出现;第三阶段,行业标准的形成有助于积累遗产代码资源和培训与推广资源;第四阶段,随着大量遗产代码开始积累,行业商业模式成型,倾向于使用成熟的程序设计语言。分析程序设计语言所处的发展阶段有助于我们了解甚至预测其发展规律。 + +\subsection{应用驱动的程序设计语言发展} + +\begin{figure}[htbp] + \centering + \includegraphics[width=0.80\textwidth]{fig1-2/2-2.png} + \caption{程序设计语言的发展及分类} + \label{fig:2-2} +\end{figure} + +这里以多个有代表性的典型语言为例,分析其应用背景、设计特点与发展规律,从而展现程序语言发展的现状、预测未来发展趋势。按照程序语言的类型与应用,图\ref{fig:2-2}给出了以时间为主线的不同类别语言的发展过程与分类关系。从不同角度来看,一种程序语言既可能属于系统编程语言,又是面向对象语言。从发展过程来看,一种语言在发展过程中会不断进行扩充,融入不同的范式,进而趋近于多范式语言。本节主要以应用驱动来组织。计算机产业的发展往往是新的产业应用从已有的应用模式中成长出来而不是取而代之。新语言的出现往往标志着信息技术在新的应用领域的扩张。 + +\begin{itemize} + \item 科学与工程计算(1954~) +\end{itemize} + +早期计算机系统硬件结构简单,软件专用性强,主要用于核反应计算、密码破译这样专业性强的科学与工程计算领域,直接服务对象往往是政府与军工。1956年发布的Fortran语言标志着具有完整工具链的程序设计语言出现。Fortran语言符合典型的过程式语言的特征,由从事系统结构和系统软件的研究人员设计,采取编译的方式实现,反映了程序设计与计算机系统之间的紧密联系。尽管串行的科学计算软件开发方法已成熟,积累的大量遗产代码保证了Fortran这样的语言在其适用领域仍然具有生命力。 + +早期语言的准确语义往往依赖于编译器的实现,针对特定体系结构由编译器的开发者设计。1950年代末期出现了一些由计算机逻辑理论与程序语义研究者设计和实现的程序设计语言,如ALGOL和LISP语言。此后出现的大量函数式语言如Haskell、ML往往具有清楚而简洁的数学表示,设计出发点上更多地考虑如何优美地表示计算,但由于缺乏工业级应用的针对性以及性能上对常见体系结构的适配性,其接受范围受到限制。 + +科学与工程性质的计算,尤其是高性能计算往往与计算机体系结构密切相关,发展了多种形式的编程接口。OpenMP是共享内存的并行计算所常用的编程接口。其特点是在C或Fortran中插入指导语句,希望不改变原有串行程序语义的条件下利用共享存储器的多线程并行加速计算。MPI是跨平台的消息传递通讯程序库,完全不增加额外的语法机制。图形处理器语言CUDA在C基础上扩展了一些语法机制,用以区分在CPU、GPU上运行的程序片段,作出不同的编译。并行程序设计模型一直是程序设计理论研究的一个重点 。 + +\begin{itemize} + \item 商用计算(1960~) +\end{itemize} + +信息技术的应用逐渐从专业领域扩展到广阔的商业领域信息化。COBOL语言的出现标志着商业化的事务处理如金融、财会有了强有力的语言技术支持。该时期计算系统往往是大型机或小型机服务器。COBOL拥有庞大的用户群,据称积累了超过2000亿行遗产代码\footnote{http://cobolcowboys.com/cobol-today/}。由于商业计算的多样性,一台大型机往往需要运行多种类型的软件,甚至同时并发地运行不同软件。这一时期开始,管理不同类型软件的操作系统得以发展。C语言可以直接处理系统资源,尤其适合系统软件开发。相比之下,同样是过程式语言的PASCAL语言则是由程序设计语言理论研究者设计的更加安全和规范的语言。数据库查询语言SQL是较早出现的领域专用语言。它不具有完整的程序设计语言功能,但可看成是针对关系数据库应用的编程模型。 + +随着商用计算而来的是软件大规模化。1960年代末出现了一系列旨在有效控制大规模软件开发过程复杂性的程序设计思想。面向对象的思想及其第一个语言Simula67试图对不同程序模块访问共享变量的方式进行限制,使得程序更加具有模块组装特性。Dijkstra提出避免使用GOTO语句的结构化程序设计思想[3],对程序的控制流进行限制。 + +\begin{itemize} + \item 人工智能(1960~) +\end{itemize} + +人工智能自诞生以来,广受关注。在该领域也出现了若干专用语言。人工智能有符号主义、连接主义等流派。 + +符号主义就是以符号逻辑系统为基础来表示知识。二十世纪七十年代,Robert Kowalski 等人提出了逻辑可以作为程序设计语言的基本思想,把逻辑和计算这两个截然不同的概念统一在一起。这就是逻辑程序设计(logic programming),而Prolog语言就是典型的逻辑程序设计语言。对经典的逻辑程序设计语言,可以进行各种扩充。例如,将状态转移的控制机制引入到时序逻辑系统的XYZ/E是世界上第一个可执行的时序逻辑程序设计语言[9]。 + +连接主义的代表是试图模拟人脑的人工神经网络。近十年来,深度学习显示出了强大的学习能力和广泛的应用前景。TensorFlow、PyTorch等工具针对深度神经网络学习算法的特点,利用高级语言展开生成神经网络结构然后以高性能方式运行学习算法。这些多样的领域特定语言工具不具备完整的通用程序设计语言功能,但十分适合特定的应用场景。 + +\begin{itemize} + \item 个人计算与系统编程(1981~) +\end{itemize} + +在摩尔定律背景下,计算机硬件系统的价格不断下降,个人使用计算机的情形越来越普遍。随个人计算而来的是软件的多样化,应用形式从事务处理和业务处理扩展到教育与娱乐。软件的开发与销售形式从硬件捆绑式发展到专业软件企业发行软件拷贝的销售形式。软件开发团队与人员的数目大量增加。C++是C语言的面向对象扩展,逐渐成为实施传统软件工程的主流语言。 + +作为一种新的多范式语言,Rust不仅能够提供友好的编译器和清晰的错误提示信息,而且速度快、内存利用率高,同时具有丰富的类型系统保证内存安全和线程安全。目前从初创公司到大型企业,已有很多公司都在使用 Rust,应用范围不仅包括嵌入式设备,也包括可扩展的 Web 服务。 + +\begin{itemize} + \item Web服务与移动计算(1990~) +\end{itemize} + +伴随互联网的出现,Web服务软件一改拷贝销售形式,直接通过互联网向终端用户提供服务。其服务形式多样,方式多变。服务的反应速度往往受限于互联网的带宽与延迟,而不是计算的速度。因此,客户端与服务器端交互程序设计语言重点关注软件的开发效率,而不是程序的性能。典型的支持此类应用的脚本语言如JavaScript、PHP已然形成工业标准。 + +1990年代后智能手机的出现与普及将计算拓展到个人随身携带的新模式。一些为Web服务设计的语言仍然适用,但新的应用形式也带来了新的挑战。许多项目需要同时以网页、平板以及智能手机形式提供服务。由于应用需求与服务逻辑的易变性,软件的任何更新希望在不同平台上一致地更新。针对这些挑战,出现了新的语言如HTML5。它们不仅需要支持复杂的功能,还需要解决跨平台、跨设备、跨操作系统兼容可移植的难题。 + +\begin{itemize} + \item 大数据分析与处理(2004~) +\end{itemize} + +平台系统的大规模数据分析与处理需求,首先来自于互联网的搜索服务。其特点是大量采集的数据需要多台服务器的集群通过并行计算高速处理。分布式并行计算带来了性能优化与可靠性的挑战。但是,在平台建设期无法预知随时可能出现的各种数据分析需求。应用开发人员需要随时针对应用需求快速、灵活地编程,而不必为系统级的性能与可靠性问题所困扰。 + +设计易用而且高效的并行程序设计语言,是数十年来计算机科学的一个难题。2004年谷歌公司发布MapReduce[1],标志着工具化的大数据编程框架出现。其设计思想是将数据集的操作限制为并行函数式语言中最基本和常用的Map和Reduce两个命令。对个体数据项的处理由应用开发人员使用C和Java这样的通用语言来编程,而数据集层次的操作由担任分布式操作系统角色的运行时系统负责执行。Hadoop和Spark是基于MapReduce的主要开源工具。尽管此类语言工具不具有独立的语法系统,但其功能和语义直接反映了并行函数式语言与过程式语言混合的编程模型,实质上起到了程序设计语言的作用。 + +增加语言的专用性有助于在保证易编程性的前提下优化性能,但如果一个编程模型不能涵盖同一应用领域多种相互联系的计算需求,其专用性会影响行业标准的形成。基本的Map与Reduce命令还不能涵盖一般的并行计算步骤的数据依赖关系。 + +\begin{itemize} + \item 互联网金融(2009~) +\end{itemize} + +以软件为核心的互联网金融指的是以互联网为载体的金融服务形式,而并非仅仅将互联网作为连接客户的信息系统。开源软件技术主导的金融服务形式始于2009年出现的第一个数字货币--比特币。数字货币以去中心化共识的区块链记账技术为基础,提供类似法定货币的金融功能,具有特殊的金融服务属性。以太坊数字货币扩展了记账技术,支持区块链中记录完整的程序并以可验证的方式执行这样的程序:合同即是程序,程序即是合同。这就是所谓的智能合约(smart contract)。Solidity是目前最流行的合约编程语言。Solidity语法类似于JavaScript,支持继承、类和复杂的用户定义类型,通过编译的方式生成以太坊虚拟机中的代码。 + +\section{程序设计语言及相关理论} +程序设计语言都具有语法和语义。同时,程序的行为可以描述为状态的转移过程。这里将讨论程序设计语言的语法与语义基础,并给出保证程序正确性的分析方法。 + +\subsection{类型论} +在很多程序设计语言中,变量与数据是带类型的;而类型之间有一定的关联。人们在研究程序设计语言理论时,可以借鉴类型论(type theory, 也称“类型理论”)来研究程序语言的类型系统。类型论是数理逻辑中的一个分支,其中的马丁洛夫类型理论用规则来刻画类型及行为,是程序构造的形式理论。类型理论研究的是程序语言的类型系统,用于定义如何将编程语言中的数值和表达式等短语归类为许多不同的类型,如何操作这些类型,这些类型如何互相作用。类型通过预测程序部件的某些执行行为来协调这些部件间的交互。在类型化的程序语言中,语言构造分为引入和消去两种形式。类型的引入形式确定该类型的值或范式,而消去形式则确定如何操作该类型的值以形成另一种(可能是相同的)类型的计算。例如,可以使用类型系统中的归纳类型定义如自然数、表、树等数据结构;使用多态类型处理程序的特定型与参数型这些不同的输入类型;使用记录类型定义一组记录的命名类型等;自然数类型的引入形式是自然数,消去形式是加法和乘法等。 + +\subsection{形式语言} +程序设计语言都有自己的词法和语法,而词法和语法的定义是一系列规则的集合,这些规则的基础就是形式语言。文法是形式语言中十分重要的基本概念,是定义描述语言的语法结构的一组形式规则。文法有四种分类,其中最常用的为正则语言和上下文无关语言。正则语言可以用正规式定义,上下文无关语言可以用上下文无关文法(元素和规则的集合)定义。程序设计语言中的大多数算术表达式可用上下文无关文法生成。正则语言是最简单的语言类,是上下文无关语言类的一个真子类。正则语言已应用于计算机程序语言编译的词法分析、开关电路设计等方面。对程序设计语言编写的程序进行分析和处理(编译)时,需要判断对应的句子是否合法,可以通过对应语言的自动机进行判断。自动机是语言的另一种表示方法。其中,正则语言可以转换成有限状态自动机、上下文无关语言可转换成下推自动机表示,反之亦然。针对某种特定输入的一系列有限的规则,对不同的输入的元素,自动机依据自身的状态会做出不同的响应,最后达到某种特定的状态。 + +\subsection{形式语义学} +给定一个程序,如何判断它是否正确?这是很早以前人们就关注的问题。简单来说,如果一个程序恰当地实现了设计者与用户的意图,它就是正确的。严格意义上,程序的正确性[6]需要数学证明,不仅需要形式描述设计者与用户的意图,而且要形式描述程序的含义,并推导程序的行为满足设计者与用户的意图。程序含义的形式化描述就是形式语义学。基于形式语义,不仅可以构建描述程序含义的基础,还可以用于验证程序的正确性。 + +程序设计语言的语法是符号化的,语义是该语言程序所描述的计算或过程。根据语义,程序设计语言的解释器或编译器可以将该语言程序编译成计算机可处理的机器语言程序。在程序设计语言的早期,人们使用自然语言解释语义。这种自然语言解释的语义不精确、有歧义,无法分析和证明程序的正确性。为了提高程序设计语言的可理解性、支持语言标准化、指导语言设计、辅助编译器开发、证明程序的性质和程序之间的等价性,需要对程序设计语言的语义进行抽象,给出严格的定义。为此,人们开始研究使用数学结构定义程序设计语言的语义,并扩展出各类形式规约(specification)语言[19],形成了形式语义学[8]。 + +\begin{itemize} + \item 操作语义 +\end{itemize} +程序运行中变量赋值的变化、行为的变迁可以通过操作语义进行描述。操作语义(operational semantics)将语言中各个成分翻译成计算机系统中相应的一组操作。目前最为常见的操作语义是标号迁移系统(labeled transition system),将程序执行描述成标号迁移系统,其中的状态是程序执行期间任意时刻观察到的变量取值。迁移规则规定如何从一个状态转换到下一个状态,每条迁移规则对应一个语句,称为标号。一条语句的语义由一组以其为标号的规则定义;标号规则具有组合性,即一个复合语句的规则可以由其成分语句的规则组合而成。例如,针对一个C程序中的循环语句while(x=y) goto out; + if (x